Merge "Fix typo on NanoAppState documentation"
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 349802c..b9673f2 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1543,11 +1543,25 @@
          *
          * <p>Note that trigger URIs can not be used in combination with
          * {@link #setPeriodic(long)} or {@link #setPersisted(boolean)}.  To continually monitor
-         * for content changes, you need to schedule a new JobInfo observing the same URIs
-         * before you finish execution of the JobService handling the most recent changes.
+         * for content changes, you need to schedule a new JobInfo using the same job ID and
+         * observing the same URIs in place of calling
+         * {@link JobService#jobFinished(JobParameters, boolean)}. Remember that
+         * {@link JobScheduler#schedule(JobInfo)} stops a running job if it uses the same job ID,
+         * so only call it after you've finished processing the most recent changes (in other words,
+         * call {@link JobScheduler#schedule(JobInfo)} where you would have normally called
+         * {@link JobService#jobFinished(JobParameters, boolean)}.
          * Following this pattern will ensure you do not lose any content changes: while your
          * job is running, the system will continue monitoring for content changes, and propagate
-         * any it sees over to the next job you schedule.</p>
+         * any changes it sees over to the next job you schedule, so you do not have to worry
+         * about missing new changes. <b>Scheduling the new job
+         * before or during processing will cause the current job to be stopped (as described in
+         * {@link JobScheduler#schedule(JobInfo)}), meaning the wakelock will be released for the
+         * current job and your app process may be killed since it will no longer be in a valid
+         * component lifecycle.</b>
+         * Since {@link JobScheduler#schedule(JobInfo)} stops the current job, you do not
+         * need to call {@link JobService#jobFinished(JobParameters, boolean)} if you call
+         * {@link JobScheduler#schedule(JobInfo)} using the same job ID as the
+         * currently running job.</p>
          *
          * <p>Because setting this property is not compatible with periodic or
          * persisted jobs, doing so will throw an {@link java.lang.IllegalArgumentException} when
diff --git a/core/api/current.txt b/core/api/current.txt
index 0e1a00f..69c4259 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9312,10 +9312,10 @@
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void disconnect();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean discoverServices();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean executeReliableWrite();
-    method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
-    method public int getConnectionState(android.bluetooth.BluetoothDevice);
+    method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+    method @Deprecated public int getConnectionState(android.bluetooth.BluetoothDevice);
     method public android.bluetooth.BluetoothDevice getDevice();
-    method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+    method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
     method public android.bluetooth.BluetoothGattService getService(java.util.UUID);
     method public java.util.List<android.bluetooth.BluetoothGattService> getServices();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
@@ -27305,11 +27305,13 @@
     method @NonNull public android.net.VpnService.Builder addDnsServer(@NonNull java.net.InetAddress);
     method @NonNull public android.net.VpnService.Builder addDnsServer(@NonNull String);
     method @NonNull public android.net.VpnService.Builder addRoute(@NonNull java.net.InetAddress, int);
+    method @NonNull public android.net.VpnService.Builder addRoute(@NonNull android.net.IpPrefix);
     method @NonNull public android.net.VpnService.Builder addRoute(@NonNull String, int);
     method @NonNull public android.net.VpnService.Builder addSearchDomain(@NonNull String);
     method @NonNull public android.net.VpnService.Builder allowBypass();
     method @NonNull public android.net.VpnService.Builder allowFamily(int);
     method @Nullable public android.os.ParcelFileDescriptor establish();
+    method @NonNull public android.net.VpnService.Builder excludeRoute(@NonNull android.net.IpPrefix);
     method @NonNull public android.net.VpnService.Builder setBlocking(boolean);
     method @NonNull public android.net.VpnService.Builder setConfigureIntent(@NonNull android.app.PendingIntent);
     method @NonNull public android.net.VpnService.Builder setHttpProxy(@NonNull android.net.ProxyInfo);
@@ -37894,6 +37896,28 @@
     method @Deprecated @NonNull public android.security.KeyPairGeneratorSpec.Builder setSubject(@NonNull javax.security.auth.x500.X500Principal);
   }
 
+  public class KeyStoreException extends java.lang.Exception {
+    method public int getNumericErrorCode();
+    method public boolean isSystemError();
+    method public boolean isTransientFailure();
+    method public boolean requiresUserAuthentication();
+    field public static final int ERROR_ATTESTATION_CHALLENGE_TOO_LARGE = 9; // 0x9
+    field public static final int ERROR_ID_ATTESTATION_FAILURE = 8; // 0x8
+    field public static final int ERROR_INCORRECT_USAGE = 13; // 0xd
+    field public static final int ERROR_INTERNAL_SYSTEM_ERROR = 4; // 0x4
+    field public static final int ERROR_KEYMINT_FAILURE = 10; // 0xa
+    field public static final int ERROR_KEYSTORE_FAILURE = 11; // 0xb
+    field public static final int ERROR_KEYSTORE_UNINITIALIZED = 3; // 0x3
+    field public static final int ERROR_KEY_CORRUPTED = 7; // 0x7
+    field public static final int ERROR_KEY_DOES_NOT_EXIST = 6; // 0x6
+    field public static final int ERROR_KEY_NOT_TEMPORALLY_VALID = 14; // 0xe
+    field public static final int ERROR_KEY_OPERATION_EXPIRED = 15; // 0xf
+    field public static final int ERROR_OTHER = 1; // 0x1
+    field public static final int ERROR_PERMISSION_DENIED = 5; // 0x5
+    field public static final int ERROR_UNIMPLEMENTED = 12; // 0xc
+    field public static final int ERROR_USER_AUTHENTICATION_REQUIRED = 2; // 0x2
+  }
+
   @Deprecated public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
     method @Deprecated public boolean isEncryptionRequired();
   }
@@ -38728,9 +38752,11 @@
 
   public abstract class CarrierService extends android.app.Service {
     ctor public CarrierService();
-    method public final void notifyCarrierNetworkChange(boolean);
+    method @Deprecated public final void notifyCarrierNetworkChange(boolean);
+    method public final void notifyCarrierNetworkChange(int, boolean);
     method @CallSuper public android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.os.PersistableBundle onLoadConfig(android.service.carrier.CarrierIdentifier);
+    method @Deprecated public abstract android.os.PersistableBundle onLoadConfig(android.service.carrier.CarrierIdentifier);
+    method @Nullable public android.os.PersistableBundle onLoadConfig(int, @Nullable android.service.carrier.CarrierIdentifier);
     field public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService";
   }
 
@@ -43444,6 +43470,7 @@
     field public static final int DATA_ENABLED_REASON_USER = 0; // 0x0
     field public static final int DATA_SUSPENDED = 3; // 0x3
     field public static final int DATA_UNKNOWN = -1; // 0xffffffff
+    field public static final int DEFAULT_PORT_INDEX = 0; // 0x0
     field public static final int ERI_FLASH = 2; // 0x2
     field public static final int ERI_OFF = 1; // 0x1
     field public static final int ERI_ON = 0; // 0x0
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 7756906..a51d2b1 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -349,6 +349,7 @@
 package android.os.storage {
 
   public class StorageManager {
+    method public long computeStorageCacheBytes(@NonNull java.io.File);
     method public void notifyAppIoBlocked(@NonNull java.util.UUID, int, int, int);
     method public void notifyAppIoResumed(@NonNull java.util.UUID, int, int, int);
     field public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 1; // 0x1
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 4700ce5..4aee6cc 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -973,7 +973,8 @@
   }
 
   public class DevicePolicyManager {
-    method public int checkProvisioningPreCondition(@NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int checkProvisioningPreCondition(@NonNull String, @NonNull String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
     method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
@@ -995,6 +996,7 @@
     method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
     method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
     method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
     method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
@@ -1062,6 +1064,65 @@
     field public static final int STATE_USER_UNMANAGED = 0; // 0x0
   }
 
+  public final class FullyManagedDeviceProvisioningParams implements android.os.Parcelable {
+    method public boolean canDeviceOwnerGrantSensorsPermissions();
+    method public int describeContents();
+    method @NonNull public android.content.ComponentName getDeviceAdminComponentName();
+    method public long getLocalTime();
+    method @Nullable public java.util.Locale getLocale();
+    method @NonNull public String getOwnerName();
+    method @Nullable public String getTimeZone();
+    method public boolean isLeaveAllSystemAppsEnabled();
+    method public void writeToParcel(@NonNull android.os.Parcel, @Nullable int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.FullyManagedDeviceProvisioningParams> CREATOR;
+  }
+
+  public static final class FullyManagedDeviceProvisioningParams.Builder {
+    ctor public FullyManagedDeviceProvisioningParams.Builder(@NonNull android.content.ComponentName, @NonNull String);
+    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams build();
+    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setCanDeviceOwnerGrantSensorsPermissions(boolean);
+    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLeaveAllSystemAppsEnabled(boolean);
+    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLocalTime(long);
+    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLocale(@Nullable java.util.Locale);
+    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setTimeZone(@Nullable String);
+  }
+
+  public final class ManagedProfileProvisioningParams implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.accounts.Account getAccountToMigrate();
+    method @NonNull public String getOwnerName();
+    method @NonNull public android.content.ComponentName getProfileAdminComponentName();
+    method @Nullable public String getProfileName();
+    method public boolean isKeepingAccountOnMigration();
+    method public boolean isLeaveAllSystemAppsEnabled();
+    method public boolean isOrganizationOwnedProvisioning();
+    method public void writeToParcel(@NonNull android.os.Parcel, @Nullable int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.ManagedProfileProvisioningParams> CREATOR;
+  }
+
+  public static final class ManagedProfileProvisioningParams.Builder {
+    ctor public ManagedProfileProvisioningParams.Builder(@NonNull android.content.ComponentName, @NonNull String);
+    method @NonNull public android.app.admin.ManagedProfileProvisioningParams build();
+    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setAccountToMigrate(@Nullable android.accounts.Account);
+    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setKeepingAccountOnMigration(boolean);
+    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setLeaveAllSystemAppsEnabled(boolean);
+    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setOrganizationOwnedProvisioning(boolean);
+    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setProfileName(@Nullable String);
+  }
+
+  public class ProvisioningException extends android.util.AndroidException {
+    ctor public ProvisioningException(@NonNull Exception, int);
+    method public int getProvisioningError();
+    field public static final int ERROR_ADMIN_PACKAGE_INSTALLATION_FAILED = 3; // 0x3
+    field public static final int ERROR_PRE_CONDITION_FAILED = 1; // 0x1
+    field public static final int ERROR_PROFILE_CREATION_FAILED = 2; // 0x2
+    field public static final int ERROR_REMOVE_NON_REQUIRED_APPS_FAILED = 6; // 0x6
+    field public static final int ERROR_SETTING_PROFILE_OWNER_FAILED = 4; // 0x4
+    field public static final int ERROR_SET_DEVICE_OWNER_FAILED = 7; // 0x7
+    field public static final int ERROR_STARTING_PROFILE_FAILED = 5; // 0x5
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+  }
+
   public final class SystemUpdatePolicy implements android.os.Parcelable {
     method public android.app.admin.SystemUpdatePolicy.InstallationOption getInstallationOptionAt(long);
     field public static final int TYPE_PAUSE = 4; // 0x4
@@ -12252,6 +12313,14 @@
     field public static final int ROAMING_TYPE_UNKNOWN = 1; // 0x1
   }
 
+  public final class SignalStrengthUpdateRequest implements android.os.Parcelable {
+    method public boolean isSystemThresholdReportingRequestedWhileIdle();
+  }
+
+  public static final class SignalStrengthUpdateRequest.Builder {
+    method @NonNull @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public android.telephony.SignalStrengthUpdateRequest.Builder setSystemThresholdReportingRequestedWhileIdle(boolean);
+  }
+
   public final class SmsCbCmasInfo implements android.os.Parcelable {
     ctor public SmsCbCmasInfo(int, int, int, int, int, int);
     method public int describeContents();
@@ -12571,6 +12640,8 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageName();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageNameForLogicalSlot(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorDisplayNumber();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int);
@@ -13182,6 +13253,7 @@
     method public void removeNotificationFromList(String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
     method public void requestAllProfiles(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo[]>);
     method public void requestDefaultSmdpAddress(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>);
+    method public void requestEnabledProfileForPort(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
     method public void requestEuiccChallenge(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
     method public void requestEuiccInfo1(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
     method public void requestEuiccInfo2(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
@@ -13205,6 +13277,7 @@
     field public static final int RESULT_CALLER_NOT_ALLOWED = -3; // 0xfffffffd
     field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe
     field public static final int RESULT_OK = 0; // 0x0
+    field public static final int RESULT_PROFILE_NOT_FOUND = -4; // 0xfffffffc
     field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
   }
 
@@ -13789,6 +13862,7 @@
     method public void disableIms(int);
     method public void enableIms(int);
     method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
+    method @NonNull public java.util.concurrent.Executor getExecutor();
     method public long getImsServiceCapabilities();
     method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
     method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int);
@@ -14407,6 +14481,7 @@
 
   public class MmTelFeature extends android.telephony.ims.feature.ImsFeature {
     ctor public MmTelFeature();
+    ctor public MmTelFeature(@NonNull java.util.concurrent.Executor);
     method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
     method public void changeOfferedRtpHeaderExtensionTypes(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtensionType>);
     method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
@@ -14440,7 +14515,7 @@
   }
 
   public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
-    ctor @Deprecated public RcsFeature();
+    ctor public RcsFeature();
     ctor public RcsFeature(@NonNull java.util.concurrent.Executor);
     method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
     method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
@@ -14545,6 +14620,7 @@
   }
 
   public class ImsConfigImplBase {
+    ctor public ImsConfigImplBase(@NonNull java.util.concurrent.Executor);
     ctor public ImsConfigImplBase();
     method public int getConfigInt(int);
     method public String getConfigString(int);
@@ -14597,6 +14673,7 @@
 
   public class ImsRegistrationImplBase {
     ctor public ImsRegistrationImplBase();
+    ctor public ImsRegistrationImplBase(@NonNull java.util.concurrent.Executor);
     method public final void onDeregistered(android.telephony.ims.ImsReasonInfo);
     method public final void onRegistered(int);
     method public final void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
@@ -14709,6 +14786,7 @@
   }
 
   public class SipTransportImplBase {
+    ctor public SipTransportImplBase();
     ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor);
     method public void createSipDelegate(int, @NonNull android.telephony.ims.DelegateRequest, @NonNull android.telephony.ims.DelegateStateCallback, @NonNull android.telephony.ims.DelegateMessageCallback);
     method public void destroySipDelegate(@NonNull android.telephony.ims.stub.SipDelegate, int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index fd11567..89dc678 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -444,7 +444,6 @@
   public class DevicePolicyManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void clearOrganizationId();
     method @RequiresPermission(android.Manifest.permission.CLEAR_FREEZE_PERIOD) public void clearSystemUpdatePolicyFreezePeriodRecord();
-    method @Nullable public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException;
     method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs();
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void forceRemoveActiveAdmin(@NonNull android.content.ComponentName, int);
     method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceSecurityLogs();
@@ -461,7 +460,6 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}, conditional=true) public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull android.content.ComponentName);
     method @NonNull public static String operationSafetyReasonToString(int);
     method @NonNull public static String operationToString(int);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void resetDefaultCrossProfileIntentFilters(int);
     method @RequiresPermission(allOf={android.Manifest.permission.MANAGE_DEVICE_ADMINS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setActiveAdmin(@NonNull android.content.ComponentName, boolean, int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean setDeviceOwner(@NonNull android.content.ComponentName, @Nullable String, int);
@@ -511,66 +509,6 @@
     field public static final int OPERATION_SWITCH_USER = 2; // 0x2
     field public static final int OPERATION_UNINSTALL_CA_CERT = 40; // 0x28
     field public static final int OPERATION_WIPE_DATA = 8; // 0x8
-    field public static final int PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED = 3; // 0x3
-    field public static final int PROVISIONING_RESULT_PRE_CONDITION_FAILED = 1; // 0x1
-    field public static final int PROVISIONING_RESULT_PROFILE_CREATION_FAILED = 2; // 0x2
-    field public static final int PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED = 6; // 0x6
-    field public static final int PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED = 4; // 0x4
-    field public static final int PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED = 7; // 0x7
-    field public static final int PROVISIONING_RESULT_STARTING_PROFILE_FAILED = 5; // 0x5
-  }
-
-  public final class FullyManagedDeviceProvisioningParams implements android.os.Parcelable {
-    method public boolean canDeviceOwnerGrantSensorsPermissions();
-    method public int describeContents();
-    method @NonNull public android.content.ComponentName getDeviceAdminComponentName();
-    method public long getLocalTime();
-    method @Nullable public java.util.Locale getLocale();
-    method @NonNull public String getOwnerName();
-    method @Nullable public String getTimeZone();
-    method public boolean isLeaveAllSystemAppsEnabled();
-    method public void logParams(@NonNull String);
-    method public void writeToParcel(@NonNull android.os.Parcel, @Nullable int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.FullyManagedDeviceProvisioningParams> CREATOR;
-  }
-
-  public static final class FullyManagedDeviceProvisioningParams.Builder {
-    ctor public FullyManagedDeviceProvisioningParams.Builder(@NonNull android.content.ComponentName, @NonNull String);
-    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams build();
-    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setDeviceOwnerCanGrantSensorsPermissions(boolean);
-    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLeaveAllSystemAppsEnabled(boolean);
-    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLocalTime(long);
-    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setLocale(@Nullable java.util.Locale);
-    method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setTimeZone(@Nullable String);
-  }
-
-  public final class ManagedProfileProvisioningParams implements android.os.Parcelable {
-    method public int describeContents();
-    method @Nullable public android.accounts.Account getAccountToMigrate();
-    method @NonNull public String getOwnerName();
-    method @NonNull public android.content.ComponentName getProfileAdminComponentName();
-    method @Nullable public String getProfileName();
-    method public boolean isKeepAccountMigrated();
-    method public boolean isLeaveAllSystemAppsEnabled();
-    method public boolean isOrganizationOwnedProvisioning();
-    method public void logParams(@NonNull String);
-    method public void writeToParcel(@NonNull android.os.Parcel, @Nullable int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.ManagedProfileProvisioningParams> CREATOR;
-  }
-
-  public static final class ManagedProfileProvisioningParams.Builder {
-    ctor public ManagedProfileProvisioningParams.Builder(@NonNull android.content.ComponentName, @NonNull String);
-    method @NonNull public android.app.admin.ManagedProfileProvisioningParams build();
-    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setAccountToMigrate(@Nullable android.accounts.Account);
-    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setKeepAccountMigrated(boolean);
-    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setLeaveAllSystemAppsEnabled(boolean);
-    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setOrganizationOwnedProvisioning(boolean);
-    method @NonNull public android.app.admin.ManagedProfileProvisioningParams.Builder setProfileName(@Nullable String);
-  }
-
-  public class ProvisioningException extends android.util.AndroidException {
-    ctor public ProvisioningException(@NonNull Exception, int);
-    method public int getProvisioningResult();
   }
 
   public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
@@ -1976,6 +1914,7 @@
   }
 
   public class StorageManager {
+    method public long computeStorageCacheBytes(@NonNull java.io.File);
     method @NonNull public static java.util.UUID convert(@NonNull String);
     method @NonNull public static String convert(@NonNull java.util.UUID);
     method public boolean isAppIoBlocked(@NonNull java.util.UUID, int, int, int);
@@ -2214,8 +2153,8 @@
   }
 
   public class KeyStoreException extends java.lang.Exception {
-    ctor public KeyStoreException(int, String);
     method public int getErrorCode();
+    method public static boolean hasFailureInfoForError(int);
   }
 
 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 5002a59..85ddff9 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -136,6 +136,7 @@
 import android.net.IEthernetManager;
 import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
+import android.net.INetworkStatsService;
 import android.net.IPacProxyManager;
 import android.net.IVpnManager;
 import android.net.IpSecManager;
@@ -227,6 +228,8 @@
 import android.view.contentcapture.IContentCaptureManager;
 import android.view.displayhash.DisplayHashManager;
 import android.view.inputmethod.InputMethodManager;
+import android.view.selectiontoolbar.ISelectionToolbarManager;
+import android.view.selectiontoolbar.SelectionToolbarManager;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textservice.TextServicesManager;
 import android.view.translation.ITranslationManager;
@@ -366,6 +369,15 @@
                 return new TextClassificationManager(ctx);
             }});
 
+        registerService(Context.SELECTION_TOOLBAR_SERVICE, SelectionToolbarManager.class,
+                new CachedServiceFetcher<SelectionToolbarManager>() {
+                    @Override
+                    public SelectionToolbarManager createService(ContextImpl ctx) {
+                        IBinder b = ServiceManager.getService(Context.SELECTION_TOOLBAR_SERVICE);
+                        return new SelectionToolbarManager(ctx.getOuterContext(),
+                                ISelectionToolbarManager.Stub.asInterface(b));
+                    }});
+
         registerService(Context.FONT_SERVICE, FontManager.class,
                 new CachedServiceFetcher<FontManager>() {
             @Override
@@ -1002,7 +1014,11 @@
                 new CachedServiceFetcher<NetworkStatsManager>() {
             @Override
             public NetworkStatsManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                return new NetworkStatsManager(ctx.getOuterContext());
+                // TODO: Replace with an initializer in the module, see
+                //  {@code ConnectivityFrameworkInitializer}.
+                final INetworkStatsService service = INetworkStatsService.Stub.asInterface(
+                        ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE));
+                return new NetworkStatsManager(ctx.getOuterContext(), service);
             }});
 
         registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ba28283..7969cda 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2354,88 +2354,6 @@
     public @interface ProvisioningPreCondition {}
 
     /**
-     * Service-specific error code for {@link #provisionFullyManagedDevice} and
-     * {@link #createAndProvisionManagedProfile}:
-     * Indicates the call to {@link #checkProvisioningPreCondition} returned an error code.
-     *
-     * @hide
-     */
-    @TestApi
-    public static final int PROVISIONING_RESULT_PRE_CONDITION_FAILED = 1;
-
-    /**
-     * Service-specific error code for {@link #createAndProvisionManagedProfile}:
-     * Indicates the call to {@link UserManager#createProfileForUserEvenWhenDisallowed}
-     * returned {@code null}.
-     *
-     * @hide
-     */
-    @TestApi
-    public static final int PROVISIONING_RESULT_PROFILE_CREATION_FAILED = 2;
-
-    /**
-     * Service-specific error code for {@link #createAndProvisionManagedProfile}:
-     * Indicates the call to {@link PackageManager#installExistingPackageAsUser} has failed.
-     *
-     * @hide
-     */
-    @TestApi
-    public static final int PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED = 3;
-
-    /**
-     * Service-specific error code for {@link #createAndProvisionManagedProfile}:
-     * Indicates the call to {@link #setProfileOwner} returned {@code false}.
-     *
-     * @hide
-     */
-    @TestApi
-    public static final int PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED = 4;
-
-    /**
-     * Service-specific error code for {@link #createAndProvisionManagedProfile}:
-     * Indicates that starting the newly created profile has failed.
-     *
-     * @hide
-     */
-    @TestApi
-    public static final int PROVISIONING_RESULT_STARTING_PROFILE_FAILED = 5;
-
-    /**
-     * Service-specific error code for {@link #provisionFullyManagedDevice}:
-     * Indicates that removing the non required apps have failed.
-     *
-     * @hide
-     */
-    @TestApi
-    public static final int PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED = 6;
-
-    /**
-     * Service-specific error code for {@link #provisionFullyManagedDevice}:
-     * Indicates the call to {@link #setDeviceOwner} returned {@code false}.
-     *
-     * @hide
-     */
-    @TestApi
-    public static final int PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED = 7;
-
-    /**
-     * Service-specific error codes for {@link #createAndProvisionManagedProfile} and
-     * {@link #provisionFullyManagedDevice} indicating all the errors during provisioning.
-     *
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "PROVISIONING_RESULT_" }, value = {
-            PROVISIONING_RESULT_PRE_CONDITION_FAILED, PROVISIONING_RESULT_PROFILE_CREATION_FAILED,
-            PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED,
-            PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED,
-            PROVISIONING_RESULT_STARTING_PROFILE_FAILED,
-            PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED,
-            PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED
-    })
-    public @interface ProvisioningResult {}
-
-    /**
      * Disable all configurable SystemUI features during LockTask mode. This includes,
      * <ul>
      *     <li>system info area in the status bar (connectivity icons, clock, etc.)
@@ -5821,13 +5739,23 @@
             "android.app.action.CHECK_POLICY_COMPLIANCE";
 
     /**
-     * Broadcast action: notify managed provisioning that new managed user is created.
+     * Broadcast action: notify managed provisioning that PO/DO provisioning has completed.
      *
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_MANAGED_USER_CREATED =
-            "android.app.action.MANAGED_USER_CREATED";
+    public static final String ACTION_PROVISIONING_COMPLETED =
+            "android.app.action.PROVISIONING_COMPLETED";
+
+    /**
+     * Extra for {@link #ACTION_PROVISIONING_COMPLETED} to indicate the provisioning action that has
+     * been completed, this can either be {@link #ACTION_PROVISION_MANAGED_PROFILE},
+     * {@link #ACTION_PROVISION_MANAGED_DEVICE}, or {@link #ACTION_PROVISION_MANAGED_USER}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_PROVISIONING_ACTION =
+            "android.app.extra.PROVISIONING_ACTION";
 
     /**
      * Broadcast action: notify system that a new (Android) user was added when the device is
@@ -11424,6 +11352,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
     public @ProvisioningPreCondition int checkProvisioningPreCondition(
             @NonNull String action, @NonNull String packageName) {
         try {
@@ -14125,7 +14054,8 @@
      * @hide
      */
     @Nullable
-    @TestApi
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
     public UserHandle createAndProvisionManagedProfile(
             @NonNull ManagedProfileProvisioningParams provisioningParams)
             throws ProvisioningException {
@@ -14158,7 +14088,7 @@
      *
      * @hide
      */
-    @TestApi
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
     public void provisionFullyManagedDevice(
             @NonNull FullyManagedDeviceProvisioningParams provisioningParams)
diff --git a/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
index 80655dd..8c232c0 100644
--- a/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
+++ b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
@@ -21,7 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -32,9 +32,10 @@
 /**
  * Params required to provision a fully managed device, see
  * {@link DevicePolicyManager#provisionFullyManagedDevice}.
+ *
  * @hide
  */
-@TestApi
+@SystemApi
 public final class FullyManagedDeviceProvisioningParams implements Parcelable {
     private static final String LEAVE_ALL_SYSTEM_APPS_ENABLED_PARAM =
             "LEAVE_ALL_SYSTEM_APPS_ENABLED";
@@ -92,29 +93,50 @@
         return localeStr == null ? null : Locale.forLanguageTag(localeStr);
     }
 
+    /**
+     * Returns the device owner's {@link ComponentName}.
+     */
     @NonNull
     public ComponentName getDeviceAdminComponentName() {
         return mDeviceAdminComponentName;
     }
 
+    /**
+     * Returns the device owner's name.
+     */
     @NonNull
     public String getOwnerName() {
         return mOwnerName;
     }
 
+    /**
+     * Returns {@code true} if system apps should be left enabled after provisioning.
+     */
     public boolean isLeaveAllSystemAppsEnabled() {
         return mLeaveAllSystemAppsEnabled;
     }
 
+    /**
+     * If set, it returns the time zone to set for the device after provisioning, otherwise returns
+     * {@code null};
+     */
     @Nullable
     public String getTimeZone() {
         return mTimeZone;
     }
 
+    /**
+     * If set, it returns the local time to set for the device after provisioning, otherwise returns
+     * 0.
+     */
     public long getLocalTime() {
         return mLocalTime;
     }
 
+    /**
+     * If set, it returns the {@link Locale} to set for the device after provisioning, otherwise
+     * returns {@code null}.
+     */
     @Nullable
     public @SuppressLint("UseIcu") Locale getLocale() {
         return mLocale;
@@ -130,6 +152,8 @@
 
     /**
      * Logs the provisioning params using {@link DevicePolicyEventLogger}.
+     *
+     * @hide
      */
     public void logParams(@NonNull String callerPackage) {
         requireNonNull(callerPackage);
@@ -232,8 +256,7 @@
          * See {@link DevicePolicyManager#EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT}.
          */
         @NonNull
-        @SuppressLint("MissingGetterMatchingBuilder")
-        public Builder setDeviceOwnerCanGrantSensorsPermissions(boolean mayGrant) {
+        public Builder setCanDeviceOwnerGrantSensorsPermissions(boolean mayGrant) {
             mDeviceOwnerCanGrantSensorsPermissions = mayGrant;
             return this;
         }
@@ -261,6 +284,9 @@
         return 0;
     }
 
+    /**
+     * @hide
+     */
     @Override
     public String toString() {
         return "FullyManagedDeviceProvisioningParams{"
diff --git a/core/java/android/app/admin/ManagedProfileProvisioningParams.java b/core/java/android/app/admin/ManagedProfileProvisioningParams.java
index 1a6099a..ccbef73 100644
--- a/core/java/android/app/admin/ManagedProfileProvisioningParams.java
+++ b/core/java/android/app/admin/ManagedProfileProvisioningParams.java
@@ -21,7 +21,7 @@
 import android.accounts.Account;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,7 +33,7 @@
  *
  * @hide
  */
-@TestApi
+@SystemApi
 public final class ManagedProfileProvisioningParams implements Parcelable {
     private static final String LEAVE_ALL_SYSTEM_APPS_ENABLED_PARAM =
             "LEAVE_ALL_SYSTEM_APPS_ENABLED";
@@ -48,7 +48,7 @@
     @Nullable private final Account mAccountToMigrate;
     private final boolean mLeaveAllSystemAppsEnabled;
     private final boolean mOrganizationOwnedProvisioning;
-    private final boolean mKeepAccountMigrated;
+    private final boolean mKeepAccountOnMigration;
 
 
     private ManagedProfileProvisioningParams(
@@ -58,50 +58,75 @@
             @Nullable Account accountToMigrate,
             boolean leaveAllSystemAppsEnabled,
             boolean organizationOwnedProvisioning,
-            boolean keepAccountMigrated) {
+            boolean keepAccountOnMigration) {
         this.mProfileAdminComponentName = requireNonNull(profileAdminComponentName);
         this.mOwnerName = requireNonNull(ownerName);
         this.mProfileName = profileName;
         this.mAccountToMigrate = accountToMigrate;
         this.mLeaveAllSystemAppsEnabled = leaveAllSystemAppsEnabled;
         this.mOrganizationOwnedProvisioning = organizationOwnedProvisioning;
-        this.mKeepAccountMigrated = keepAccountMigrated;
+        this.mKeepAccountOnMigration = keepAccountOnMigration;
     }
 
+    /**
+     * Returns the profile owner's {@link ComponentName}.
+     */
     @NonNull
     public ComponentName getProfileAdminComponentName() {
         return mProfileAdminComponentName;
     }
 
+    /**
+     * Returns the profile owner's name.
+     */
     @NonNull
     public String getOwnerName() {
         return mOwnerName;
     }
 
+    /**
+     * Returns the profile's name if set, otherwise returns {@code null}.
+     */
     @Nullable
     public String getProfileName() {
         return mProfileName;
     }
 
+    /**
+     * If set, it returns the {@link Account} to migrate from the parent profile to the managed
+     * profile after provisioning, otherwise returns {@code null}.
+     */
     @Nullable
     public Account getAccountToMigrate() {
         return mAccountToMigrate;
     }
 
+    /**
+     * Returns {@code true} if system apps should be left enabled after provisioning.
+     */
     public boolean isLeaveAllSystemAppsEnabled() {
         return mLeaveAllSystemAppsEnabled;
     }
 
+    /**
+     * Returns {@code true} if this is an org owned device.
+     */
     public boolean isOrganizationOwnedProvisioning() {
         return mOrganizationOwnedProvisioning;
     }
 
-    public boolean isKeepAccountMigrated() {
-        return mKeepAccountMigrated;
+    /**
+     * Returns {@code true} if the migrated account from {@link #getAccountToMigrate()} should be
+     * kept in parent profile.
+     */
+    public boolean isKeepingAccountOnMigration() {
+        return mKeepAccountOnMigration;
     }
 
     /**
      * Logs the provisioning params using {@link DevicePolicyEventLogger}.
+     *
+     * @hide
      */
     public void logParams(@NonNull String callerPackage) {
         requireNonNull(callerPackage);
@@ -109,7 +134,7 @@
         logParam(callerPackage, LEAVE_ALL_SYSTEM_APPS_ENABLED_PARAM, mLeaveAllSystemAppsEnabled);
         logParam(callerPackage, ORGANIZATION_OWNED_PROVISIONING_PARAM,
                 mOrganizationOwnedProvisioning);
-        logParam(callerPackage, KEEP_MIGRATED_ACCOUNT_PARAM, mKeepAccountMigrated);
+        logParam(callerPackage, KEEP_MIGRATED_ACCOUNT_PARAM, mKeepAccountOnMigration);
         logParam(callerPackage, ACCOUNT_TO_MIGRATE_PROVIDED_PARAM,
                 /* value= */ mAccountToMigrate != null);
     }
@@ -134,7 +159,7 @@
         @Nullable private Account mAccountToMigrate;
         private boolean mLeaveAllSystemAppsEnabled;
         private boolean mOrganizationOwnedProvisioning;
-        private boolean mKeepAccountMigrated;
+        private boolean mKeepingAccountOnMigration;
 
         /**
          * Initialize a new {@link Builder) to construct a {@link ManagedProfileProvisioningParams}.
@@ -204,8 +229,8 @@
          * Defaults to {@code false}.
          */
         @NonNull
-        public Builder setKeepAccountMigrated(boolean keepAccountMigrated) {
-            this.mKeepAccountMigrated = keepAccountMigrated;
+        public Builder setKeepingAccountOnMigration(boolean keepingAccountOnMigration) {
+            this.mKeepingAccountOnMigration = keepingAccountOnMigration;
             return this;
         }
 
@@ -223,7 +248,7 @@
                     mAccountToMigrate,
                     mLeaveAllSystemAppsEnabled,
                     mOrganizationOwnedProvisioning,
-                    mKeepAccountMigrated);
+                    mKeepingAccountOnMigration);
         }
     }
 
@@ -232,6 +257,9 @@
         return 0;
     }
 
+    /**
+     * @hide
+     */
     @Override
     public String toString() {
         return "ManagedProfileProvisioningParams{"
@@ -241,7 +269,7 @@
                 + ", mAccountToMigrate=" + (mAccountToMigrate == null ? "null" : mAccountToMigrate)
                 + ", mLeaveAllSystemAppsEnabled=" + mLeaveAllSystemAppsEnabled
                 + ", mOrganizationOwnedProvisioning=" + mOrganizationOwnedProvisioning
-                + ", mKeepAccountMigrated=" + mKeepAccountMigrated
+                + ", mKeepAccountOnMigration=" + mKeepAccountOnMigration
                 + '}';
     }
 
@@ -253,7 +281,7 @@
         dest.writeTypedObject(mAccountToMigrate, flags);
         dest.writeBoolean(mLeaveAllSystemAppsEnabled);
         dest.writeBoolean(mOrganizationOwnedProvisioning);
-        dest.writeBoolean(mKeepAccountMigrated);
+        dest.writeBoolean(mKeepAccountOnMigration);
     }
 
     public static final @NonNull Creator<ManagedProfileProvisioningParams> CREATOR =
diff --git a/core/java/android/app/admin/ProvisioningException.java b/core/java/android/app/admin/ProvisioningException.java
index 639859b..d374c16 100644
--- a/core/java/android/app/admin/ProvisioningException.java
+++ b/core/java/android/app/admin/ProvisioningException.java
@@ -15,10 +15,15 @@
  */
 
 package android.app.admin;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.TestApi;
+import android.annotation.SystemApi;
+import android.content.pm.PackageManager;
 import android.util.AndroidException;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Thrown to indicate a failure during {@link DevicePolicyManager#provisionFullyManagedDevice} and
  * {@link DevicePolicyManager#createAndProvisionManagedProfile}.
@@ -26,17 +31,88 @@
  * @hide
  *
  */
-@TestApi
+@SystemApi
 public class ProvisioningException extends AndroidException {
-    private final @DevicePolicyManager.ProvisioningResult int mProvisioningResult;
+
+    /**
+     * Service-specific error code for {@link DevicePolicyManager#provisionFullyManagedDevice} and
+     * {@link DevicePolicyManager#createAndProvisionManagedProfile}:
+     * Indicates a generic failure.
+     */
+    public static final int ERROR_UNKNOWN = 0;
+
+    /**
+     * Service-specific error code for {@link DevicePolicyManager#provisionFullyManagedDevice} and
+     * {@link DevicePolicyManager#createAndProvisionManagedProfile}:
+     * Indicates the call to {@link DevicePolicyManager#checkProvisioningPreCondition} returned an
+     * error code.
+     */
+    public static final int ERROR_PRE_CONDITION_FAILED = 1;
+
+    /**
+     * Service-specific error code for {@link DevicePolicyManager#createAndProvisionManagedProfile}:
+     * Indicates that the profile creation failed.
+     */
+    public static final int ERROR_PROFILE_CREATION_FAILED = 2;
+
+    /**
+     * Service-specific error code for {@link DevicePolicyManager#createAndProvisionManagedProfile}:
+     * Indicates the call to {@link PackageManager#installExistingPackageAsUser} has failed.
+     */
+    public static final int ERROR_ADMIN_PACKAGE_INSTALLATION_FAILED = 3;
+
+    /**
+     * Service-specific error code for {@link DevicePolicyManager#createAndProvisionManagedProfile}:
+     * Indicates that setting the profile owner failed.
+     */
+    public static final int ERROR_SETTING_PROFILE_OWNER_FAILED = 4;
+
+    /**
+     * Service-specific error code for {@link DevicePolicyManager#createAndProvisionManagedProfile}:
+     * Indicates that starting the newly created profile has failed.
+     */
+    public static final int ERROR_STARTING_PROFILE_FAILED = 5;
+
+    /**
+     * Service-specific error code for {@link DevicePolicyManager#provisionFullyManagedDevice}:
+     * Indicates that removing the non required apps have failed.
+     */
+    public static final int ERROR_REMOVE_NON_REQUIRED_APPS_FAILED = 6;
+
+    /**
+     * Service-specific error code for {@link DevicePolicyManager#provisionFullyManagedDevice}:
+     * Indicates that setting the device owner failed.
+     */
+    public static final int ERROR_SET_DEVICE_OWNER_FAILED = 7;
+
+    /**
+     * Service-specific error codes for {@link DevicePolicyManager#createAndProvisionManagedProfile}
+     * and {@link DevicePolicyManager#provisionFullyManagedDevice} indicating all the errors
+     * during provisioning.
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "ERROR_" }, value = {
+            ERROR_UNKNOWN, ERROR_PRE_CONDITION_FAILED,
+            ERROR_PROFILE_CREATION_FAILED,
+            ERROR_ADMIN_PACKAGE_INSTALLATION_FAILED,
+            ERROR_SETTING_PROFILE_OWNER_FAILED,
+            ERROR_STARTING_PROFILE_FAILED,
+            ERROR_REMOVE_NON_REQUIRED_APPS_FAILED,
+            ERROR_SET_DEVICE_OWNER_FAILED
+    })
+    public @interface ProvisioningError {}
+
+    private final @ProvisioningError int mProvisioningError;
 
     public ProvisioningException(@NonNull Exception cause,
-            @DevicePolicyManager.ProvisioningResult int provisioningResult) {
+            @ProvisioningError int provisioningError) {
         super(cause);
-        mProvisioningResult = provisioningResult;
+        mProvisioningError = provisioningError;
     }
 
-    public @DevicePolicyManager.ProvisioningResult int getProvisioningResult() {
-        return mProvisioningResult;
+    public @ProvisioningError int getProvisioningError() {
+        return mProvisioningError;
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 4e7c01a..fe8d1ba 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -1806,32 +1806,33 @@
     }
 
     /**
-     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
      * with {@link BluetoothProfile#GATT} as argument
-     *
      * @throws UnsupportedOperationException
      */
     @Override
     @RequiresNoPermission
+    @Deprecated
     public int getConnectionState(BluetoothDevice device) {
         throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
     }
 
     /**
-     * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
+     * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
      * with {@link BluetoothProfile#GATT} as argument
      *
      * @throws UnsupportedOperationException
      */
     @Override
     @RequiresNoPermission
+    @Deprecated
     public List<BluetoothDevice> getConnectedDevices() {
         throw new UnsupportedOperationException(
                 "Use BluetoothManager#getConnectedDevices instead.");
     }
 
     /**
-     * Not supported - please use
+     * @deprecated Not supported - please use
      * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
      * with {@link BluetoothProfile#GATT} as first argument
      *
@@ -1839,6 +1840,7 @@
      */
     @Override
     @RequiresNoPermission
+    @Deprecated
     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
         throw new UnsupportedOperationException(
                 "Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index f913349..540e5a7 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -514,16 +514,27 @@
         @Override
         public void onScanResult(final ScanResult scanResult) {
             Attributable.setAttributionSource(scanResult, mAttributionSource);
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "onScanResult() - mScannerId=" + mScannerId);
+            }
             if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString());
 
             // Check null in case the scan has been stopped
             synchronized (this) {
-                if (mScannerId <= 0) return;
+                if (mScannerId <= 0) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Ignoring result as scan stopped.");
+                    }
+                    return;
+                };
             }
             Handler handler = new Handler(Looper.getMainLooper());
             handler.post(new Runnable() {
                 @Override
                 public void run() {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "onScanResult() - handler run");
+                    }
                     mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
                 }
             });
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index f335ae4..d46a0c6 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -392,7 +392,7 @@
         PendingResult res = mPendingResult;
         mPendingResult = null;
 
-        if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+        if (res != null && Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
             res.mReceiverClassName = getClass().getName();
             Trace.traceCounter(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                     "BroadcastReceiver#goAsync#ClassName:" + res.mReceiverClassName,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 543239b..6d13712 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4790,6 +4790,15 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.view.selectiontoolbar.SelectionToolbarManager} for selection toolbar service.
+     *
+     * @see #getSystemService(String)
+     * @hide
+     */
+    public static final String SELECTION_TOOLBAR_SERVICE = "selection_toolbar";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.graphics.fonts.FontManager} for font services.
      *
      * @see #getSystemService(String)
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 2ced056..1ae1b05 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -41,6 +41,7 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.net.NetworkUtilsInternal;
 import com.android.internal.net.VpnConfig;
 
@@ -50,6 +51,7 @@
 import java.net.InetAddress;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -471,6 +473,13 @@
         }
     }
 
+    private static void checkNonPrefixBytes(@NonNull InetAddress address, int prefixLength) {
+        final IpPrefix prefix = new IpPrefix(address, prefixLength);
+        if (!prefix.getAddress().equals(address)) {
+            throw new IllegalArgumentException("Bad address");
+        }
+    }
+
     /**
      * Helper class to create a VPN interface. This class should be always
      * used within the scope of the outer {@link VpnService}.
@@ -481,9 +490,9 @@
 
         private final VpnConfig mConfig = new VpnConfig();
         @UnsupportedAppUsage
-        private final List<LinkAddress> mAddresses = new ArrayList<LinkAddress>();
+        private final List<LinkAddress> mAddresses = new ArrayList<>();
         @UnsupportedAppUsage
-        private final List<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+        private final List<RouteInfo> mRoutes = new ArrayList<>();
 
         public Builder() {
             mConfig.user = VpnService.this.getClass().getName();
@@ -555,7 +564,6 @@
                 throw new IllegalArgumentException("Bad address");
             }
             mAddresses.add(new LinkAddress(address, prefixLength));
-            mConfig.updateAllowedFamilies(address);
             return this;
         }
 
@@ -579,28 +587,68 @@
          * Add a network route to the VPN interface. Both IPv4 and IPv6
          * routes are supported.
          *
+         * If a route with the same destination is already present, its type will be updated.
+         *
+         * @throws IllegalArgumentException if the route is invalid.
+         */
+        @NonNull
+        private Builder addRoute(@NonNull IpPrefix prefix, int type) {
+            check(prefix.getAddress(), prefix.getPrefixLength());
+
+            final RouteInfo newRoute = new RouteInfo(prefix, /* gateway */
+                    null, /* interface */ null, type);
+
+            final int index = findRouteIndexByDestination(newRoute);
+
+            if (index == -1) {
+                mRoutes.add(newRoute);
+            } else {
+                mRoutes.set(index, newRoute);
+            }
+
+            return this;
+        }
+
+        /**
+         * Add a network route to the VPN interface. Both IPv4 and IPv6
+         * routes are supported.
+         *
          * Adding a route implicitly allows traffic from that address family
          * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
          *
+         * Calling this method overrides previous calls to {@link #excludeRoute} for the same
+         * destination.
+         *
+         * If multiple routes match the packet destination, route with the longest prefix takes
+         * precedence.
+         *
          * @throws IllegalArgumentException if the route is invalid.
          */
         @NonNull
         public Builder addRoute(@NonNull InetAddress address, int prefixLength) {
-            check(address, prefixLength);
+            checkNonPrefixBytes(address, prefixLength);
 
-            int offset = prefixLength / 8;
-            byte[] bytes = address.getAddress();
-            if (offset < bytes.length) {
-                for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) {
-                    if (bytes[offset] != 0) {
-                        throw new IllegalArgumentException("Bad address");
-                    }
-                }
-            }
-            mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null, null,
-                RouteInfo.RTN_UNICAST));
-            mConfig.updateAllowedFamilies(address);
-            return this;
+            return addRoute(new IpPrefix(address, prefixLength), RouteInfo.RTN_UNICAST);
+        }
+
+        /**
+         * Add a network route to the VPN interface. Both IPv4 and IPv6
+         * routes are supported.
+         *
+         * Adding a route implicitly allows traffic from that address family
+         * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
+         *
+         * Calling this method overrides previous calls to {@link #excludeRoute} for the same
+         * destination.
+         *
+         * If multiple routes match the packet destination, route with the longest prefix takes
+         * precedence.
+         *
+         * @throws IllegalArgumentException if the route is invalid.
+         */
+        @NonNull
+        public Builder addRoute(@NonNull IpPrefix prefix) {
+            return addRoute(prefix, RouteInfo.RTN_UNICAST);
         }
 
         /**
@@ -611,6 +659,12 @@
          * Adding a route implicitly allows traffic from that address family
          * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
          *
+         * Calling this method overrides previous calls to {@link #excludeRoute} for the same
+         * destination.
+         *
+         * If multiple routes match the packet destination, route with the longest prefix takes
+         * precedence.
+         *
          * @throws IllegalArgumentException if the route is invalid.
          * @see #addRoute(InetAddress, int)
          */
@@ -620,6 +674,23 @@
         }
 
         /**
+         * Exclude a network route from the VPN interface. Both IPv4 and IPv6
+         * routes are supported.
+         *
+         * Calling this method overrides previous calls to {@link #addRoute} for the same
+         * destination.
+         *
+         * If multiple routes match the packet destination, route with the longest prefix takes
+         * precedence.
+         *
+         * @throws IllegalArgumentException if the route is invalid.
+         */
+        @NonNull
+        public Builder excludeRoute(@NonNull IpPrefix prefix) {
+            return addRoute(prefix, RouteInfo.RTN_THROW);
+        }
+
+        /**
          * Add a DNS server to the VPN connection. Both IPv4 and IPv6
          * addresses are supported. If none is set, the DNS servers of
          * the default network will be used.
@@ -900,5 +971,23 @@
                 throw new IllegalStateException(e);
             }
         }
+
+        private int findRouteIndexByDestination(RouteInfo route) {
+            for (int i = 0; i < mRoutes.size(); i++) {
+                if (mRoutes.get(i).getDestination().equals(route.getDestination())) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        /**
+         * Method for testing, to observe mRoutes while builder is being used.
+         * @hide
+         */
+        @VisibleForTesting
+        public List<RouteInfo> routes() {
+            return Collections.unmodifiableList(mRoutes);
+        }
     }
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index adf7955c..5e4057b 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1437,11 +1437,36 @@
         throw new IllegalStateException("Missing primary storage");
     }
 
-    private static final int DEFAULT_THRESHOLD_PERCENTAGE = 5;
-    private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
+    /**
+     * Devices having above STORAGE_THRESHOLD_PERCENT_HIGH of total space free are considered to be
+     * in high free space category.
+     *
+     * @hide
+     */
+    public static final int STORAGE_THRESHOLD_PERCENT_HIGH = 20;
+    /**
+     * Devices having below STORAGE_THRESHOLD_PERCENT_LOW of total space free are considered to be
+     * in low free space category.
+     *
+     * @hide
+     */
+    public static final int STORAGE_THRESHOLD_PERCENT_LOW = 5;
+    /**
+     * For devices in high free space category, CACHE_RESERVE_PERCENT_HIGH percent of total space is
+     * allocated for cache.
+     *
+     * @hide
+     */
+    public static final int CACHE_RESERVE_PERCENT_HIGH = 10;
+    /**
+     * For devices in low free space category, CACHE_RESERVE_PERCENT_LOW percent of total space is
+     * allocated for cache.
+     *
+     * @hide
+     */
+    public static final int CACHE_RESERVE_PERCENT_LOW = 2;
 
-    private static final int DEFAULT_CACHE_PERCENTAGE = 10;
-    private static final long DEFAULT_CACHE_MAX_BYTES = DataUnit.GIBIBYTES.toBytes(5);
+    private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
 
     private static final long DEFAULT_FULL_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(1);
 
@@ -1465,7 +1490,7 @@
     @UnsupportedAppUsage
     public long getStorageLowBytes(File path) {
         final long lowPercent = Settings.Global.getInt(mResolver,
-                Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
+                Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, STORAGE_THRESHOLD_PERCENT_LOW);
         final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
 
         final long maxLowBytes = Settings.Global.getLong(mResolver,
@@ -1475,28 +1500,54 @@
     }
 
     /**
+     * Compute the minimum number of bytes of storage on the device that could
+     * be reserved for cached data depending on the device state which is then passed on
+     * to getStorageCacheBytes.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    @TestApi
+    @SuppressLint("StreamFiles")
+    public long computeStorageCacheBytes(@NonNull File path) {
+        final long totalBytes = path.getTotalSpace();
+        final long usableBytes = path.getUsableSpace();
+        final long storageThresholdHighBytes = totalBytes * STORAGE_THRESHOLD_PERCENT_HIGH / 100;
+        final long storageThresholdLowBytes = getStorageLowBytes(path);
+        long result;
+        if (usableBytes > storageThresholdHighBytes) {
+            // If free space is >STORAGE_THRESHOLD_PERCENT_HIGH of total space,
+            // reserve CACHE_RESERVE_PERCENT_HIGH of total space
+            result = totalBytes * CACHE_RESERVE_PERCENT_HIGH / 100;
+        } else if (usableBytes < storageThresholdLowBytes) {
+            // If free space is <min(STORAGE_THRESHOLD_PERCENT_LOW of total space, 500MB),
+            // reserve CACHE_RESERVE_PERCENT_LOW of total space
+            result = totalBytes * CACHE_RESERVE_PERCENT_LOW / 100;
+        } else {
+            // Else, linearly interpolate the amount of space to reserve
+            result = ((CACHE_RESERVE_PERCENT_HIGH - CACHE_RESERVE_PERCENT_LOW)
+                      * (usableBytes - storageThresholdHighBytes) + CACHE_RESERVE_PERCENT_HIGH
+                      * (storageThresholdHighBytes - storageThresholdLowBytes)) * totalBytes
+                      / (100 * (storageThresholdHighBytes - storageThresholdLowBytes));
+        }
+        return result;
+    }
+
+    /**
      * Return the minimum number of bytes of storage on the device that should
      * be reserved for cached data.
      *
      * @hide
      */
-    public long getStorageCacheBytes(File path, @AllocateFlags int flags) {
-        final long cachePercent = Settings.Global.getInt(mResolver,
-                Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE, DEFAULT_CACHE_PERCENTAGE);
-        final long cacheBytes = (path.getTotalSpace() * cachePercent) / 100;
-
-        final long maxCacheBytes = Settings.Global.getLong(mResolver,
-                Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, DEFAULT_CACHE_MAX_BYTES);
-
-        final long result = Math.min(cacheBytes, maxCacheBytes);
+    public long getStorageCacheBytes(@NonNull File path, @AllocateFlags int flags) {
         if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
             return 0;
         } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) {
             return 0;
         } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) {
-            return result / 2;
+            return computeStorageCacheBytes(path) / 2;
         } else {
-            return result;
+            return computeStorageCacheBytes(path);
         }
     }
 
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 50a44a1..a00dd51 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -5317,6 +5317,13 @@
         public static final String COLUMN_PROFILE_CLASS = "profile_class";
 
         /**
+         * TelephonyProvider column name for the port index of the active UICC port.
+         * <P>Type: INTEGER (int)</P>
+         * @hide
+         */
+        public static final String COLUMN_PORT_INDEX = "port_index";
+
+        /**
          * A testing profile can be pre-loaded or downloaded onto
          * the eUICC and provides connectivity to test equipment
          * for the purpose of testing the device and the eUICC. It
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 3b4f7e2..f900558 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -317,16 +317,35 @@
             ErrorCode.MISSING_MIN_MAC_LENGTH; // -58;
     public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH =
             ErrorCode.UNSUPPORTED_MIN_MAC_LENGTH; // -59;
+    public static final int KM_ERROR_UNSUPPORTED_KDF = ErrorCode.UNSUPPORTED_KDF; // -60
+    public static final int KM_ERROR_UNSUPPORTED_EC_CURVE = ErrorCode.UNSUPPORTED_EC_CURVE; // -61
+    // -62 is KEY_REQUIRES_UPGRADE and is handled by Keystore.
+    public static final int KM_ERROR_ATTESTATION_CHALLENGE_MISSING =
+            ErrorCode.ATTESTATION_CHALLENGE_MISSING; // -63
+    public static final int KM_ERROR_KEYMINT_NOT_CONFIGURED =
+            ErrorCode.KEYMINT_NOT_CONFIGURED; // -64
+    public static final int KM_ERROR_ATTESTATION_APPLICATION_ID_MISSING =
+            ErrorCode.ATTESTATION_APPLICATION_ID_MISSING; // -65;
     public static final int KM_ERROR_CANNOT_ATTEST_IDS =
             ErrorCode.CANNOT_ATTEST_IDS; // -66;
+    public static final int KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE =
+            ErrorCode.ROLLBACK_RESISTANCE_UNAVAILABLE; // -67;
     public static final int KM_ERROR_HARDWARE_TYPE_UNAVAILABLE =
             ErrorCode.HARDWARE_TYPE_UNAVAILABLE; // -68;
     public static final int KM_ERROR_DEVICE_LOCKED =
             ErrorCode.DEVICE_LOCKED; // -72;
+    public static final int KM_ERROR_STORAGE_KEY_UNSUPPORTED =
+            ErrorCode.STORAGE_KEY_UNSUPPORTED; // -77,
+    public static final int KM_ERROR_INCOMPATIBLE_MGF_DIGEST =
+            ErrorCode.INCOMPATIBLE_MGF_DIGEST; // -78,
+    public static final int KM_ERROR_UNSUPPORTED_MGF_DIGEST =
+            ErrorCode.UNSUPPORTED_MGF_DIGEST; // -79,
     public static final int KM_ERROR_MISSING_NOT_BEFORE =
             ErrorCode.MISSING_NOT_BEFORE; // -80;
     public static final int KM_ERROR_MISSING_NOT_AFTER =
             ErrorCode.MISSING_NOT_AFTER; // -80;
+    public static final int KM_ERROR_HARDWARE_NOT_YET_AVAILABLE =
+            ErrorCode.HARDWARE_NOT_YET_AVAILABLE; // -85
     public static final int KM_ERROR_UNIMPLEMENTED =
             ErrorCode.UNIMPLEMENTED; // -100;
     public static final int KM_ERROR_VERSION_MISMATCH =
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 859fd80..e7f8920 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -285,6 +285,8 @@
      * UI. There is no timeout associated with showing this UX, so a carrier app must be sure to
      * call with active set to false sometime after calling with it set to {@code true}.
      * <p>
+     * This will apply to all subscriptions the carrier app has carrier privileges on.
+     * <p>
      * Requires Permission: calling app has carrier privileges.
      *
      * @param active Whether the carrier network change is or shortly will be
@@ -300,6 +302,31 @@
     }
 
     /**
+     * Informs the system of an intentional upcoming carrier network change by a carrier app on the
+     * given {@code subscriptionId}. This call only used to allow the system to provide alternative
+     * UI while telephony is performing an action that may result in intentional, temporary network
+     * lack of connectivity.
+     * <p>
+     * Based on the active parameter passed in, this method will either show or hide the
+     * alternative UI. There is no timeout associated with showing this UX, so a carrier app must be
+     * sure to call with active set to false sometime after calling with it set to {@code true}.
+     * <p>
+     * Requires Permission: calling app has carrier privileges.
+     *
+     * @param subscriptionId the subscription of the carrier network.
+     * @param active whether the carrier network change is or shortly will be active. Set this value
+     *              to true to begin showing alternative UI and false to stop.
+     * @see TelephonyManager#hasCarrierPrivileges
+     */
+    public void notifyCarrierNetworkChange(int subscriptionId, boolean active) {
+        try {
+            sRegistry.notifyCarrierNetworkChangeWithSubId(subscriptionId, active);
+        } catch (RemoteException ex) {
+            // system server crash
+        }
+    }
+
+    /**
      * Notify call state changed on certain subscription.
      *
      * @param slotIndex for which call state changed. Can be derived from subId except when subId is
diff --git a/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl b/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl
new file mode 100644
index 0000000..0e8e57b
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/ISelectionToolbarCallback.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+import android.view.selectiontoolbar.ToolbarMenuItem;
+import android.view.selectiontoolbar.WidgetInfo;
+
+/**
+ * Binder interface to notify the selection toolbar events from one process to the other.
+ * @hide
+ */
+oneway interface ISelectionToolbarCallback {
+    void onShown(in WidgetInfo info);
+    void onHidden();
+    void onDismissed();
+    void onWidgetUpdated(in WidgetInfo info);
+    void onMenuItemClicked(in ToolbarMenuItem item);
+    void onError(int errorCode);
+}
diff --git a/core/java/android/view/selectiontoolbar/ISelectionToolbarManager.aidl b/core/java/android/view/selectiontoolbar/ISelectionToolbarManager.aidl
new file mode 100644
index 0000000..4a647ad
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/ISelectionToolbarManager.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+import android.view.selectiontoolbar.ISelectionToolbarCallback;
+import android.view.selectiontoolbar.ShowInfo;
+
+/**
+ * Mediator between apps and selection toolbar service implementation.
+ *
+ * @hide
+ */
+oneway interface ISelectionToolbarManager {
+    void showToolbar(in ShowInfo showInfo, in ISelectionToolbarCallback callback, int userId);
+    void hideToolbar(long widgetToken, int userId);
+    void dismissToolbar(long widgetToken, int userId);
+}
\ No newline at end of file
diff --git a/core/java/android/view/selectiontoolbar/OWNERS b/core/java/android/view/selectiontoolbar/OWNERS
new file mode 100644
index 0000000..5500b92
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 709498
+
+augale@google.com
+joannechung@google.com
+licha@google.com
+lpeter@google.com
+svetoslavganov@google.com
+toki@google.com
+tonymak@google.com
+tymtsai@google.com
\ No newline at end of file
diff --git a/core/java/android/view/selectiontoolbar/SelectionContext.aidl b/core/java/android/view/selectiontoolbar/SelectionContext.aidl
new file mode 100644
index 0000000..5206831
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/SelectionContext.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+/**
+ * @hide
+ */
+parcelable SelectionContext;
diff --git a/core/java/android/view/selectiontoolbar/SelectionContext.java b/core/java/android/view/selectiontoolbar/SelectionContext.java
new file mode 100644
index 0000000..21b8d8f
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/SelectionContext.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * The class holds information for a selection.
+ *
+ * @hide
+ */
+@DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true)
+public final class SelectionContext implements Parcelable {
+
+    /**
+     * The start index of a selection.
+     */
+    private final int mStartIndex;
+
+    /**
+     * The end index of a selection.
+     */
+    private final int mEndIndex;
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/selectiontoolbar/SelectionContext.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    /* package-private */ SelectionContext(
+            int startIndex,
+            int endIndex) {
+        this.mStartIndex = startIndex;
+        this.mEndIndex = endIndex;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The start index of a selection.
+     */
+    @DataClass.Generated.Member
+    public int getStartIndex() {
+        return mStartIndex;
+    }
+
+    /**
+     * The end index of a selection.
+     */
+    @DataClass.Generated.Member
+    public int getEndIndex() {
+        return mEndIndex;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "SelectionContext { " +
+                "startIndex = " + mStartIndex + ", " +
+                "endIndex = " + mEndIndex +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(SelectionContext other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        SelectionContext that = (SelectionContext) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mStartIndex == that.mStartIndex
+                && mEndIndex == that.mEndIndex;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + mStartIndex;
+        _hash = 31 * _hash + mEndIndex;
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mStartIndex);
+        dest.writeInt(mEndIndex);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ SelectionContext(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int startIndex = in.readInt();
+        int endIndex = in.readInt();
+
+        this.mStartIndex = startIndex;
+        this.mEndIndex = endIndex;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<SelectionContext> CREATOR
+            = new Parcelable.Creator<SelectionContext>() {
+        @Override
+        public SelectionContext[] newArray(int size) {
+            return new SelectionContext[size];
+        }
+
+        @Override
+        public SelectionContext createFromParcel(@NonNull android.os.Parcel in) {
+            return new SelectionContext(in);
+        }
+    };
+
+    /**
+     * A builder for {@link SelectionContext}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private int mStartIndex;
+        private int mEndIndex;
+
+        private long mBuilderFieldsSet = 0L;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @param startIndex
+         *   The start index of a selection.
+         * @param endIndex
+         *   The end index of a selection.
+         */
+        public Builder(
+                int startIndex,
+                int endIndex) {
+            mStartIndex = startIndex;
+            mEndIndex = endIndex;
+        }
+
+        /**
+         * The start index of a selection.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setStartIndex(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mStartIndex = value;
+            return this;
+        }
+
+        /**
+         * The end index of a selection.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setEndIndex(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mEndIndex = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull SelectionContext build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4; // Mark builder used
+
+            SelectionContext o = new SelectionContext(
+                    mStartIndex,
+                    mEndIndex);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x4) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1639488292248L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/SelectionContext.java",
+            inputSignatures = "private final  int mStartIndex\nprivate final  int mEndIndex\nclass SelectionContext extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
new file mode 100644
index 0000000..60688ea
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+import android.annotation.NonNull;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+
+import java.util.Objects;
+
+/**
+ * The {@link SelectionToolbarManager} class provides ways for apps to control the
+ * selection toolbar.
+ *
+ * @hide
+ */
+@SystemService(Context.SELECTION_TOOLBAR_SERVICE)
+public final class SelectionToolbarManager {
+
+    private static final String TAG = "SelectionToolbar";
+
+    /**
+     * The tag which uses for enabling debug log dump. To enable it, we can use command "adb shell
+     * setprop log.tag.UiTranslation DEBUG".
+     */
+    public static final String LOG_TAG = "SelectionToolbar";
+
+
+    @NonNull
+    private final Context mContext;
+    private final ISelectionToolbarManager mService;
+
+    public SelectionToolbarManager(@NonNull Context context,
+            @NonNull ISelectionToolbarManager service) {
+        mContext = Objects.requireNonNull(context);
+        mService = service;
+    }
+
+    /**
+     * Request to show selection toolbar for a given View.
+     */
+    public void showToolbar(@NonNull ShowInfo showInfo,
+            @NonNull ISelectionToolbarCallback callback) {
+        try {
+            Objects.requireNonNull(showInfo);
+            Objects.requireNonNull(callback);
+            mService.showToolbar(showInfo, callback, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Request to hide selection toolbar.
+     */
+    public void hideToolbar(long widgetToken) {
+        try {
+            mService.hideToolbar(widgetToken, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Dismiss to dismiss selection toolbar.
+     */
+    public void dismissToolbar(long widgetToken) {
+        try {
+            mService.dismissToolbar(widgetToken, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/view/selectiontoolbar/ShowInfo.aidl b/core/java/android/view/selectiontoolbar/ShowInfo.aidl
new file mode 100644
index 0000000..dce9c15
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/ShowInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+/**
+ * @hide
+ */
+parcelable ShowInfo;
diff --git a/core/java/android/view/selectiontoolbar/ShowInfo.java b/core/java/android/view/selectiontoolbar/ShowInfo.java
new file mode 100644
index 0000000..bbbd5c0
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/ShowInfo.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+
+/**
+ * The class holds menu information for render service to render the selection toolbar.
+ *
+ * @hide
+ */
+@DataClass(genToString = true, genEqualsHashCode = true)
+public final class ShowInfo implements Parcelable {
+    /**
+     * The token that is used to identify the selection toolbar. This is initially set to 0
+     * until a selection toolbar has been created for the showToolbar request.
+     */
+    private final long mWidgetToken;
+
+    // TODO: add members when the code really uses it
+
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/selectiontoolbar/ShowInfo.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new ShowInfo.
+     *
+     * @param widgetToken
+     *   The token that is used to identify the selection toolbar.
+     */
+    @DataClass.Generated.Member
+    public ShowInfo(
+            long widgetToken) {
+        this.mWidgetToken = widgetToken;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The token that is used to identify the selection toolbar.
+     */
+    @DataClass.Generated.Member
+    public long getWidgetToken() {
+        return mWidgetToken;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "ShowInfo { " +
+                "widgetToken = " + mWidgetToken +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(ShowInfo other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        ShowInfo that = (ShowInfo) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mWidgetToken == that.mWidgetToken;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Long.hashCode(mWidgetToken);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeLong(mWidgetToken);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ ShowInfo(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        long widgetToken = in.readLong();
+
+        this.mWidgetToken = widgetToken;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ShowInfo> CREATOR
+            = new Parcelable.Creator<ShowInfo>() {
+        @Override
+        public ShowInfo[] newArray(int size) {
+            return new ShowInfo[size];
+        }
+
+        @Override
+        public ShowInfo createFromParcel(@NonNull android.os.Parcel in) {
+            return new ShowInfo(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1639488262761L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/ShowInfo.java",
+            inputSignatures = "private final  long mWidgetToken\nclass ShowInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/selectiontoolbar/ToolbarMenuItem.aidl b/core/java/android/view/selectiontoolbar/ToolbarMenuItem.aidl
new file mode 100644
index 0000000..711a85a
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/ToolbarMenuItem.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+/**
+ * @hide
+ */
+parcelable ToolbarMenuItem;
diff --git a/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java b/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java
new file mode 100644
index 0000000..5af232c
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * The menu item that is used to show the selection toolbar.
+ *
+ * @hide
+ */
+@DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true)
+public final class ToolbarMenuItem implements Parcelable {
+
+    /**
+     * The id of the menu item.
+     */
+    private final int mItemId;
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    /* package-private */ ToolbarMenuItem(
+            int itemId) {
+        this.mItemId = itemId;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The id of the menu item.
+     */
+    @DataClass.Generated.Member
+    public int getItemId() {
+        return mItemId;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "ToolbarMenuItem { " +
+                "itemId = " + mItemId +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(ToolbarMenuItem other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        ToolbarMenuItem that = (ToolbarMenuItem) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mItemId == that.mItemId;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + mItemId;
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mItemId);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ ToolbarMenuItem(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int itemId = in.readInt();
+
+        this.mItemId = itemId;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<ToolbarMenuItem> CREATOR
+            = new Parcelable.Creator<ToolbarMenuItem>() {
+        @Override
+        public ToolbarMenuItem[] newArray(int size) {
+            return new ToolbarMenuItem[size];
+        }
+
+        @Override
+        public ToolbarMenuItem createFromParcel(@NonNull android.os.Parcel in) {
+            return new ToolbarMenuItem(in);
+        }
+    };
+
+    /**
+     * A builder for {@link ToolbarMenuItem}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private int mItemId;
+
+        private long mBuilderFieldsSet = 0L;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @param itemId
+         *   The id of the menu item.
+         */
+        public Builder(
+                int itemId) {
+            mItemId = itemId;
+        }
+
+        /**
+         * The id of the menu item.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setItemId(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mItemId = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull ToolbarMenuItem build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2; // Mark builder used
+
+            ToolbarMenuItem o = new ToolbarMenuItem(
+                    mItemId);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x2) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1639488328542L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/ToolbarMenuItem.java",
+            inputSignatures = "private final  int mItemId\nclass ToolbarMenuItem extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/view/selectiontoolbar/WidgetInfo.aidl b/core/java/android/view/selectiontoolbar/WidgetInfo.aidl
new file mode 100644
index 0000000..1057c51
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/WidgetInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+/**
+ * @hide
+ */
+parcelable WidgetInfo;
diff --git a/core/java/android/view/selectiontoolbar/WidgetInfo.java b/core/java/android/view/selectiontoolbar/WidgetInfo.java
new file mode 100644
index 0000000..961d8ac
--- /dev/null
+++ b/core/java/android/view/selectiontoolbar/WidgetInfo.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.selectiontoolbar;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * The class holds the rendered content and the related information from the render service to
+ * be used to show on the selection toolbar.
+ *
+ * @hide
+ */
+@DataClass(genToString = true, genEqualsHashCode = true)
+public final class WidgetInfo implements Parcelable {
+
+    /**
+     * The token that is used to identify the selection toolbar.
+     */
+    private final long mWidgetToken;
+
+    // TODO: add members when the code really uses it
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/selectiontoolbar/WidgetInfo.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new WidgetInfo.
+     *
+     * @param widgetToken
+     *   The token that is used to identify the selection toolbar.
+     */
+    @DataClass.Generated.Member
+    public WidgetInfo(
+            long widgetToken) {
+        this.mWidgetToken = widgetToken;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * The token that is used to identify the selection toolbar.
+     */
+    @DataClass.Generated.Member
+    public long getWidgetToken() {
+        return mWidgetToken;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "WidgetInfo { " +
+                "widgetToken = " + mWidgetToken +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(WidgetInfo other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        WidgetInfo that = (WidgetInfo) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && mWidgetToken == that.mWidgetToken;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Long.hashCode(mWidgetToken);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeLong(mWidgetToken);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ WidgetInfo(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        long widgetToken = in.readLong();
+
+        this.mWidgetToken = widgetToken;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<WidgetInfo> CREATOR
+            = new Parcelable.Creator<WidgetInfo>() {
+        @Override
+        public WidgetInfo[] newArray(int size) {
+            return new WidgetInfo[size];
+        }
+
+        @Override
+        public WidgetInfo createFromParcel(@NonNull android.os.Parcel in) {
+            return new WidgetInfo(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1639488254020L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/view/selectiontoolbar/WidgetInfo.java",
+            inputSignatures = "private final  long mWidgetToken\nclass WidgetInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 2a203ac..b579be0 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -34,8 +34,6 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 
-import java.net.Inet4Address;
-import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -93,8 +91,8 @@
     public String interfaze;
     public String session;
     public int mtu = -1;
-    public List<LinkAddress> addresses = new ArrayList<LinkAddress>();
-    public List<RouteInfo> routes = new ArrayList<RouteInfo>();
+    public List<LinkAddress> addresses = new ArrayList<>();
+    public List<RouteInfo> routes = new ArrayList<>();
     public List<String> dnsServers;
     public List<String> searchDomains;
     public List<String> allowedApplications;
@@ -114,12 +112,32 @@
     public VpnConfig() {
     }
 
-    public void updateAllowedFamilies(InetAddress address) {
-        if (address instanceof Inet4Address) {
-            allowIPv4 = true;
-        } else {
-            allowIPv6 = true;
-        }
+    public VpnConfig(VpnConfig other) {
+        user = other.user;
+        interfaze = other.interfaze;
+        session = other.session;
+        mtu = other.mtu;
+        addresses = copyOf(other.addresses);
+        routes = copyOf(other.routes);
+        dnsServers = copyOf(other.dnsServers);
+        searchDomains = copyOf(other.searchDomains);
+        allowedApplications = copyOf(other.allowedApplications);
+        disallowedApplications = copyOf(other.disallowedApplications);
+        configureIntent = other.configureIntent;
+        startTime = other.startTime;
+        legacy = other.legacy;
+        blocking = other.blocking;
+        allowBypass = other.allowBypass;
+        allowIPv4 = other.allowIPv4;
+        allowIPv6 = other.allowIPv6;
+        isMetered = other.isMetered;
+        underlyingNetworks = other.underlyingNetworks != null ? Arrays.copyOf(
+                other.underlyingNetworks, other.underlyingNetworks.length) : null;
+        proxyInfo = other.proxyInfo;
+    }
+
+    private static <T> List<T> copyOf(List<T> list) {
+        return list != null ? new ArrayList<>(list) : null;
     }
 
     public void addLegacyRoutes(String routesStr) {
@@ -131,7 +149,6 @@
             //each route is ip/prefix
             RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST);
             this.routes.add(info);
-            updateAllowedFamilies(info.getDestination().getAddress());
         }
     }
 
@@ -144,7 +161,6 @@
             //each address is ip/prefix
             LinkAddress addr = new LinkAddress(address);
             this.addresses.add(addr);
-            updateAllowedFamilies(addr.getAddress());
         }
     }
 
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index 4dc9aa5..a52ae10 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -589,6 +589,10 @@
         final int numIndices = mConfig.getNumberOfBuckets();
         for (int index = 0; index < numIndices; index++) {
             setValueIfSupported(index, 0L);
+            if (mAccumulatedMultiStateChargeMicroCoulomb != null
+                    && mAccumulatedMultiStateChargeMicroCoulomb[index] != null) {
+                mAccumulatedMultiStateChargeMicroCoulomb[index].reset();
+            }
         }
     }
 
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 6ba0279..15d4246 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -77,6 +77,7 @@
     void notifySubscriptionInfoChanged();
     void notifyOpportunisticSubscriptionInfoChanged();
     void notifyCarrierNetworkChange(in boolean active);
+    void notifyCarrierNetworkChangeWithSubId(in int subId, in boolean active);
     void notifyUserMobileDataStateChangedForPhoneId(in int phoneId, in int subId, in boolean state);
     void notifyDisplayInfoChanged(int slotIndex, int subId, in TelephonyDisplayInfo telephonyDisplayInfo);
     void notifyPhoneCapabilityChanged(in PhoneCapability capability);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 55c34fc..4f35f2c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3997,6 +3997,14 @@
     <permission android:name="android.permission.BIND_TEXTCLASSIFIER_SERVICE"
                 android:protectionLevel="signature" />
 
+    <!-- Must be required by a android.service.selectiontoolbar.SelectionToolbarRenderService,
+          to ensure that only the system can bind to it.
+          @hide This is not a third-party API (intended for OEMs and system apps).
+          <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_SELECTION_TOOLBAR_RENDER_SERVICE"
+                android:protectionLevel="signature" />
+
     <!-- Must be required by a android.service.contentcapture.ContentCaptureService,
          to ensure that only the system can bind to it.
          @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
index 16dcff5..7ccbb01 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
@@ -16,6 +16,10 @@
 
 package android.os.storage;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.test.InstrumentationTestCase;
@@ -23,6 +27,10 @@
 
 import libcore.io.Streams;
 
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
 import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.File;
@@ -39,6 +47,7 @@
 
     protected Context mContext = null;
     protected StorageManager mSm = null;
+    @Mock private File mFile;
     private static String LOG_TAG = "StorageManagerBaseTest";
     protected static final long MAX_WAIT_TIME = 120*1000;
     protected static final long WAIT_TIME_INCR = 5*1000;
@@ -121,12 +130,50 @@
      */
     @Override
     public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
         mContext = getInstrumentation().getContext();
         mSm = (StorageManager)mContext.getSystemService(android.content.Context.STORAGE_SERVICE);
 
     }
 
     /**
+     * Tests the space reserved for cache when system has high free space i.e. more than
+     * StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total space.
+     */
+    @Test
+    public void testGetStorageCacheBytesUnderHighStorage() throws Exception {
+        when(mFile.getUsableSpace()).thenReturn(10000L);
+        when(mFile.getTotalSpace()).thenReturn(15000L);
+        long result = mSm.getStorageCacheBytes(mFile, 0);
+        assertThat(result).isEqualTo(1500L);
+    }
+
+    /**
+     * Tests the space reserved for cache when system has low free space i.e. less than
+     * StorageManager.STORAGE_THRESHOLD_PERCENT_LOW of total space.
+     */
+    @Test
+    public void testGetStorageCacheBytesUnderLowStorage() throws Exception {
+        when(mFile.getUsableSpace()).thenReturn(10000L);
+        when(mFile.getTotalSpace()).thenReturn(250000L);
+        long result = mSm.getStorageCacheBytes(mFile, 0);
+        assertThat(result).isEqualTo(5000L);
+    }
+
+    /**
+     * Tests the space reserved for cache when system has moderate free space i.e.more than
+     * StorageManager.STORAGE_THRESHOLD_PERCENT_LOW of total space but less than
+     * StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total space.
+     */
+    @Test
+    public void testGetStorageCacheBytesUnderModerateStorage() throws Exception {
+        when(mFile.getUsableSpace()).thenReturn(10000L);
+        when(mFile.getTotalSpace()).thenReturn(100000L);
+        long result = mSm.getStorageCacheBytes(mFile, 0);
+        assertThat(result).isEqualTo(4666L);
+    }
+
+    /**
      * Creates an OBB file (with the given name), into the app's standard files directory
      *
      * @param name The name of the OBB file we want to create/write to
@@ -526,4 +573,4 @@
         doValidateIntContents(path + File.separator + "subdir2" + File.separator + "subdir2a"
                 + File.separator + "subdir2a1", "OneToOneThousandInts", 0, 1000);
     }
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
index dc5bc97..dbb2cf1 100644
--- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -465,16 +465,23 @@
         supportedStandardBuckets[POWER_BUCKET_SCREEN_DOZE] = false;
         supportedStandardBuckets[POWER_BUCKET_SCREEN_OTHER] = true;
 
+        final int[] supportedMultiStateBuckets = new int[]{POWER_BUCKET_SCREEN_ON};
         final MeasuredEnergyStats.Config config =
                 new MeasuredEnergyStats.Config(supportedStandardBuckets, customBucketNames,
-                        new int[0], new String[]{"s"});
+                        supportedMultiStateBuckets, new String[]{"s1", "s2"});
         final MeasuredEnergyStats stats = new MeasuredEnergyStats(config);
-        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10);
-        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5);
+        stats.setState(1, 0);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 10, 1000);
+        stats.updateStandardBucket(POWER_BUCKET_SCREEN_ON, 5, 2000);
         stats.updateStandardBucket(POWER_BUCKET_SCREEN_OTHER, 40);
         stats.updateCustomBucket(0, 50);
         stats.updateCustomBucket(1, 60);
 
+        assertThat(stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON, 0))
+                .isEqualTo(0);
+        assertThat(stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON, 1))
+                .isEqualTo(15);
+
         MeasuredEnergyStats.resetIfNotNull(stats);
         // All charges should be reset to 0
         for (int i = 0; i < NUMBER_STANDARD_POWER_BUCKETS; i++) {
@@ -485,7 +492,13 @@
                 assertFalse(stats.isStandardBucketSupported(i));
                 assertEquals(POWER_DATA_UNAVAILABLE, stats.getAccumulatedStandardBucketCharge(i));
             }
+
         }
+        assertThat(stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON, 0))
+                .isEqualTo(0);
+        assertThat(stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON, 1))
+                .isEqualTo(0);
+
         for (int i = 0; i < customBucketNames.length; i++) {
             assertEquals(0, stats.getAccumulatedCustomBucketCharge(i));
         }
diff --git a/keystore/java/android/security/KeyStoreException.java b/keystore/java/android/security/KeyStoreException.java
index 30389a29d..6db2745 100644
--- a/keystore/java/android/security/KeyStoreException.java
+++ b/keystore/java/android/security/KeyStoreException.java
@@ -16,25 +16,448 @@
 
 package android.security;
 
+import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.security.keymaster.KeymasterDefs;
+import android.system.keystore2.ResponseCode;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
- * KeyStore/keymaster exception with positive error codes coming from the KeyStore and negative
- * ones from keymaster.
+ * Exception containing information about the failure at the Keystore / KeyMint layer while
+ * generating or using a key.
  *
- * @hide
+ * The public error codes indicate the cause of the error and the methods indicate whether
+ * it's a system/key issue and whether re-trying the operation (with the same key or a new key)
+ * is likely to succeed.
  */
-@TestApi
 public class KeyStoreException extends Exception {
+    /**
+     * This error code is for mapping errors that the caller will not know about. If the caller is
+     * targeting an API level earlier than the one the error was introduced in, then the error will
+     * be mapped to this one.
+     * In API level 33 no errors map to this error.
+     */
+    public static final int ERROR_OTHER = 1;
+    /**
+     * Indicating the key could not be used because the user needs to authenticate first.
+     * See
+     * {@link android.security.keystore.KeyGenParameterSpec.Builder#setUserAuthenticationRequired(boolean)}.
+     */
+    public static final int ERROR_USER_AUTHENTICATION_REQUIRED = 2;
+    /**
+     * Indicating that {@code load()} has not been called on the Keystore instance, or an attempt
+     * has been made to generate an authorization bound key while the user has not set a lock
+     * screen knowledge factor (LSKF). Instruct the user to set an LSKF and retry.
+     */
+    public static final int ERROR_KEYSTORE_UNINITIALIZED = 3;
+    /**
+     * An internal system error - refer to {@link #isTransientFailure()} to determine whether
+     * re-trying the operation is likely to yield different results.
+     */
+    public static final int ERROR_INTERNAL_SYSTEM_ERROR = 4;
+    /**
+     * The caller has requested key parameters or operation which are only available to system
+     * or privileged apps.
+     */
+    public static final int ERROR_PERMISSION_DENIED = 5;
+    /**
+     * The key the operation refers to doesn't exist.
+     */
+    public static final int ERROR_KEY_DOES_NOT_EXIST = 6;
+    /**
+     * The key is corrupted and could not be recovered.
+     */
+    public static final int ERROR_KEY_CORRUPTED = 7;
+    /**
+     * The error related to inclusion of device identifiers in the attestation record.
+     */
+    public static final int ERROR_ID_ATTESTATION_FAILURE = 8;
+    /**
+     * The attestation challenge specified is too large.
+     */
+    public static final int ERROR_ATTESTATION_CHALLENGE_TOO_LARGE = 9;
+    /**
+     * General error in the KeyMint layer.
+     */
+    public static final int ERROR_KEYMINT_FAILURE = 10;
+    /**
+     * Failure in the Keystore layer.
+     */
+    public static final int ERROR_KEYSTORE_FAILURE = 11;
+    /**
+     * The feature the caller is trying to use is not implemented by the underlying
+     * KeyMint implementation.
+     * This could happen when an unsupported algorithm is requested, or when trying to import
+     * a key in a format other than raw or PKCS#8.
+     */
+    public static final int ERROR_UNIMPLEMENTED = 12;
+    /**
+     * The feature the caller is trying to use is not compatible with the parameters used to
+     * generate the key. For example, trying to use a key generated for a different signature
+     * algorithm, or a digest not specified during key creation.
+     * Another case is the attempt to generate a symmetric AES key and requesting key attestation.
+     */
+    public static final int ERROR_INCORRECT_USAGE = 13;
+    /**
+     * The key is not currently valid: Either at has expired or it will be valid for use in the
+     * future.
+     */
+    public static final int ERROR_KEY_NOT_TEMPORALLY_VALID = 14;
+    /**
+     * The crypto object the caller has been using held a reference to a KeyMint operation that
+     * has been evacuated (likely due to other concurrent operations taking place).
+     * The caller should re-create the crypto object and try again.
+     */
+    public static final int ERROR_KEY_OPERATION_EXPIRED = 15;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true, prefix = {"ERROR_"}, value = {
+            ERROR_OTHER,
+            ERROR_USER_AUTHENTICATION_REQUIRED,
+            ERROR_KEYSTORE_UNINITIALIZED,
+            ERROR_INTERNAL_SYSTEM_ERROR,
+            ERROR_PERMISSION_DENIED,
+            ERROR_KEY_DOES_NOT_EXIST,
+            ERROR_KEY_CORRUPTED,
+            ERROR_ID_ATTESTATION_FAILURE,
+            ERROR_ATTESTATION_CHALLENGE_TOO_LARGE,
+            ERROR_KEYMINT_FAILURE,
+            ERROR_KEYSTORE_FAILURE,
+            ERROR_UNIMPLEMENTED,
+            ERROR_INCORRECT_USAGE,
+            ERROR_KEY_NOT_TEMPORALLY_VALID,
+            ERROR_KEY_OPERATION_EXPIRED
+    })
+    public @interface PublicErrorCode {
+    }
+
+    // Constants for encoding information about the error encountered:
+    // Whether the error relates to the system state/implementation as a whole, or a specific key.
+    private static final int IS_SYSTEM_ERROR = 1 << 1;
+    // Whether the error is permanent.
+    private static final int IS_TRANSIENT_ERROR = 1 << 2;
+    // Whether the cause of the error is the user not having authenticated recently.
+    private static final int REQUIRES_USER_AUTHENTICATION = 1 << 3;
+
+    // The internal error code. NOT to be returned directly to callers or made part of the
+    // public API.
     private final int mErrorCode;
 
-    public KeyStoreException(int errorCode, String message) {
+    /**
+     * @hide
+     */
+    public KeyStoreException(int errorCode, @Nullable String message) {
         super(message);
         mErrorCode = errorCode;
     }
 
+    /**
+     * Returns the internal error code. Only for use by the platform.
+     *
+     * @hide
+     */
+    @TestApi
     public int getErrorCode() {
         return mErrorCode;
     }
+
+    /**
+     * Returns one of the error codes exported by the class.
+     *
+     * @return a public error code, one of the values in {@link PublicErrorCode}.
+     */
+    @PublicErrorCode
+    public int getNumericErrorCode() {
+        PublicErrorInformation failureInfo = getErrorInformation(mErrorCode);
+        return failureInfo.errorCode;
+    }
+
+    /**
+     * Returns true if the failure is a transient failure - that is, performing the same operation
+     * again at a late time is likely to succeed.
+     *
+     * If {@link #isSystemError()} returns true, the transient nature of the failure relates to the
+     * device, otherwise relates to the key (so a permanent failure with an existing key likely
+     * requires creating another key to repeat the operation with).
+     */
+    public boolean isTransientFailure() {
+        PublicErrorInformation failureInfo = getErrorInformation(mErrorCode);
+        return (failureInfo.indicators & IS_TRANSIENT_ERROR) != 0;
+    }
+
+    /**
+     * Indicates whether the failure is due to the device being locked.
+     *
+     * @return true if the key operation failed because the user has to authenticate
+     * (e.g. by unlocking the device).
+     */
+    public boolean requiresUserAuthentication() {
+        PublicErrorInformation failureInfo = getErrorInformation(mErrorCode);
+        return (failureInfo.indicators & REQUIRES_USER_AUTHENTICATION) != 0;
+    }
+
+    /**
+     * Indicates whether the error related to the Keystore/KeyMint implementation and not
+     * a specific key.
+     *
+     * @return true if the error is related to the system, not the key in use. System
+     * errors indicate a feature isn't working, whereas key-related errors are likely
+     * to succeed with a new key.
+     */
+    public boolean isSystemError() {
+        PublicErrorInformation failureInfo = getErrorInformation(mErrorCode);
+        return (failureInfo.indicators & IS_SYSTEM_ERROR) != 0;
+    }
+
+    @Override
+    public String toString() {
+        String errorCodes = String.format(" (public error code: %d internal Keystore code: %d)",
+                getNumericErrorCode(), mErrorCode);
+        return super.toString() + errorCodes;
+    }
+
+    private static PublicErrorInformation getErrorInformation(int internalErrorCode) {
+        PublicErrorInformation errorInfo = sErrorCodeToFailureInfo.get(internalErrorCode);
+        if (errorInfo != null) {
+            return errorInfo;
+        }
+
+        /**
+         * KeyStore/keymaster exception with positive error codes coming from the KeyStore and
+         * negative ones from keymaster.
+         * This is a safety fall-back: All error codes should be present in the map.
+         */
+        if (internalErrorCode > 0) {
+            return GENERAL_KEYSTORE_ERROR;
+        } else {
+            return GENERAL_KEYMINT_ERROR;
+        }
+    }
+
+    private static final class PublicErrorInformation {
+        public final int indicators;
+        public final int errorCode;
+
+        PublicErrorInformation(int indicators, @PublicErrorCode int errorCode) {
+            this.indicators = indicators;
+            this.errorCode = errorCode;
+        }
+    }
+
+    private static final PublicErrorInformation GENERAL_KEYMINT_ERROR =
+            new PublicErrorInformation(0, ERROR_KEYMINT_FAILURE);
+
+    private static final PublicErrorInformation GENERAL_KEYSTORE_ERROR =
+            new PublicErrorInformation(0, ERROR_KEYSTORE_FAILURE);
+
+    private static final PublicErrorInformation KEYMINT_UNIMPLEMENTED_ERROR =
+            new PublicErrorInformation(IS_SYSTEM_ERROR, ERROR_UNIMPLEMENTED);
+
+    private static final PublicErrorInformation KEYMINT_RETRYABLE_ERROR =
+            new PublicErrorInformation(IS_SYSTEM_ERROR | IS_TRANSIENT_ERROR,
+                    ERROR_KEYMINT_FAILURE);
+
+    private static final PublicErrorInformation KEYMINT_INCORRECT_USAGE_ERROR =
+            new PublicErrorInformation(0, ERROR_INCORRECT_USAGE);
+
+    private static final PublicErrorInformation KEYMINT_TEMPORAL_VALIDITY_ERROR =
+            new PublicErrorInformation(0, ERROR_KEY_NOT_TEMPORALLY_VALID);
+
+
+    private static final Map<Integer, PublicErrorInformation> sErrorCodeToFailureInfo =
+            new HashMap();
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public static boolean hasFailureInfoForError(int internalErrorCode) {
+        return sErrorCodeToFailureInfo.containsKey(internalErrorCode);
+    }
+
+    static {
+        // KeyMint error codes
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_OK, GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_ROOT_OF_TRUST_ALREADY_SET,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_PURPOSE,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_PURPOSE,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_ALGORITHM,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_ALGORITHM,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KEY_SIZE,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_BLOCK_MODE,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_BLOCK_MODE,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_MAC_LENGTH,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_PADDING_MODE,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_PADDING_MODE,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_DIGEST,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_DIGEST,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_EXPIRATION_TIME,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_USER_ID,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KEY_FORMAT,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_KEY_FORMAT,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KEY_VERIFICATION_ALGORITHM,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_EXPORT_OPTIONS_INVALID,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_DELEGATION_NOT_ALLOWED,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID,
+                KEYMINT_TEMPORAL_VALIDITY_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_EXPIRED,
+                KEYMINT_TEMPORAL_VALIDITY_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED,
+                new PublicErrorInformation(REQUIRES_USER_AUTHENTICATION,
+                        ERROR_USER_AUTHENTICATION_REQUIRED));
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_OUTPUT_PARAMETER_NULL,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE,
+                new PublicErrorInformation(IS_SYSTEM_ERROR | IS_TRANSIENT_ERROR,
+                        ERROR_KEY_OPERATION_EXPIRED));
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INSUFFICIENT_BUFFER_SPACE,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_VERIFICATION_FAILED,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_TOO_MANY_OPERATIONS,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNEXPECTED_NULL_POINTER,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_KEY_BLOB,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORTED_KEY_NOT_ENCRYPTED,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORTED_KEY_DECRYPTION_FAILED,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORTED_KEY_NOT_SIGNED,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORTED_KEY_VERIFICATION_FAILED,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_ARGUMENT,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_TAG,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_TAG,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MEMORY_ALLOCATION_FAILED,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_IMPORT_PARAMETER_MISMATCH,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_SECURE_HW_ACCESS_DENIED,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_OPERATION_CANCELLED,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_CONCURRENT_ACCESS_CONFLICT,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_SECURE_HW_BUSY,
+                KEYMINT_RETRYABLE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_SECURE_HW_COMMUNICATION_FAILED,
+                KEYMINT_RETRYABLE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_EC_FIELD,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_NONCE,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_NONCE,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_MAC_LENGTH,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_RATE_LIMIT_EXCEEDED,
+                KEYMINT_RETRYABLE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED,
+                GENERAL_KEYMINT_ERROR);
+        // Error related to MAX_USES_PER_BOOT, restricting the number of uses per boot.
+        // It is not re-tryable.
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEY_MAX_OPS_EXCEEDED,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INVALID_MAC_LENGTH,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_MIN_MAC_LENGTH,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_KDF,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_EC_CURVE,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_ATTESTATION_CHALLENGE_MISSING,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_KEYMINT_NOT_CONFIGURED,
+                new PublicErrorInformation(IS_SYSTEM_ERROR, ERROR_KEYMINT_FAILURE));
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_ATTESTATION_APPLICATION_ID_MISSING,
+                KEYMINT_RETRYABLE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_CANNOT_ATTEST_IDS,
+                new PublicErrorInformation(IS_SYSTEM_ERROR,
+                        ERROR_ID_ATTESTATION_FAILURE));
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_DEVICE_LOCKED,
+                new PublicErrorInformation(IS_SYSTEM_ERROR | REQUIRES_USER_AUTHENTICATION,
+                        ERROR_USER_AUTHENTICATION_REQUIRED));
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_STORAGE_KEY_UNSUPPORTED,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_INCOMPATIBLE_MGF_DIGEST,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNSUPPORTED_MGF_DIGEST,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_NOT_BEFORE,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_MISSING_NOT_AFTER,
+                KEYMINT_INCORRECT_USAGE_ERROR);
+        // This should not be exposed to apps as it's handled by Keystore.
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_HARDWARE_NOT_YET_AVAILABLE,
+                GENERAL_KEYMINT_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNIMPLEMENTED,
+                KEYMINT_UNIMPLEMENTED_ERROR);
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
+                new PublicErrorInformation(IS_SYSTEM_ERROR,
+                        ERROR_KEYMINT_FAILURE));
+        sErrorCodeToFailureInfo.put(KeymasterDefs.KM_ERROR_VERSION_MISMATCH, GENERAL_KEYMINT_ERROR);
+
+        // Keystore error codes
+        sErrorCodeToFailureInfo.put(ResponseCode.LOCKED,
+                new PublicErrorInformation(REQUIRES_USER_AUTHENTICATION,
+                        ERROR_USER_AUTHENTICATION_REQUIRED));
+        sErrorCodeToFailureInfo.put(ResponseCode.UNINITIALIZED,
+                new PublicErrorInformation(IS_SYSTEM_ERROR, ERROR_KEYSTORE_UNINITIALIZED));
+        sErrorCodeToFailureInfo.put(ResponseCode.SYSTEM_ERROR,
+                new PublicErrorInformation(IS_SYSTEM_ERROR,
+                        ERROR_INTERNAL_SYSTEM_ERROR));
+        sErrorCodeToFailureInfo.put(ResponseCode.PERMISSION_DENIED,
+                new PublicErrorInformation(0, ERROR_PERMISSION_DENIED));
+        sErrorCodeToFailureInfo.put(ResponseCode.KEY_NOT_FOUND,
+                new PublicErrorInformation(0, ERROR_KEY_DOES_NOT_EXIST));
+        sErrorCodeToFailureInfo.put(ResponseCode.VALUE_CORRUPTED,
+                new PublicErrorInformation(0, ERROR_KEY_CORRUPTED));
+        sErrorCodeToFailureInfo.put(ResponseCode.KEY_PERMANENTLY_INVALIDATED,
+                new PublicErrorInformation(0, ERROR_KEY_DOES_NOT_EXIST));
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 86e7b0e..16f4c72 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -23,6 +23,10 @@
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM;
 
+import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
+import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS;
 import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_DISMISS_SNAP;
 import static com.android.wm.shell.transition.Transitions.isOpeningType;
 
@@ -40,7 +44,9 @@
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.transition.OneShotRemoteHandler;
 import com.android.wm.shell.transition.Transitions;
 
@@ -57,7 +63,7 @@
     private final Transitions mTransitions;
     private final Runnable mOnFinish;
 
-    IBinder mPendingDismiss = null;
+    DismissTransition mPendingDismiss = null;
     IBinder mPendingEnter = null;
 
     private IBinder mAnimatingTransition = null;
@@ -127,12 +133,6 @@
                 }
                 // TODO(shell-transitions): screenshot here
                 final Rect startBounds = new Rect(change.getStartAbsBounds());
-                if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
-                    // Dismissing split via snap which means the still-visible task has been
-                    // dragged to its end position at animation start so reflect that here.
-                    startBounds.offsetTo(change.getEndAbsBounds().left,
-                            change.getEndAbsBounds().top);
-                }
                 final Rect endBounds = new Rect(change.getEndAbsBounds());
                 startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
                 endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
@@ -184,12 +184,20 @@
         return transition;
     }
 
-    /** Starts a transition for dismissing split after dragging the divider to a screen edge */
-    IBinder startSnapToDismiss(@NonNull WindowContainerTransaction wct,
-            @NonNull Transitions.TransitionHandler handler) {
-        final IBinder transition = mTransitions.startTransition(
-                TRANSIT_SPLIT_DISMISS_SNAP, wct, handler);
-        mPendingDismiss = transition;
+    /** Starts a transition to dismiss split. */
+    IBinder startDismissTransition(@Nullable IBinder transition, WindowContainerTransaction wct,
+            Transitions.TransitionHandler handler, @SplitScreen.StageType int dismissTop,
+            @SplitScreenController.ExitReason int reason) {
+        final int type = reason == EXIT_REASON_DRAG_DIVIDER
+                ? TRANSIT_SPLIT_DISMISS_SNAP : TRANSIT_SPLIT_DISMISS;
+        if (transition == null) {
+            transition = mTransitions.startTransition(type, wct, handler);
+        }
+        mPendingDismiss = new DismissTransition(transition, reason, dismissTop);
+
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
+                        + " deduced Dismiss due to %s. toTop=%s",
+                exitReasonToString(reason), stageTypeToString(dismissTop));
         return transition;
     }
 
@@ -206,7 +214,7 @@
         if (mAnimatingTransition == mPendingEnter) {
             mPendingEnter = null;
         }
-        if (mAnimatingTransition == mPendingDismiss) {
+        if (mPendingDismiss != null && mPendingDismiss.mTransition == mAnimatingTransition) {
             mPendingDismiss = null;
         }
         mAnimatingTransition = null;
@@ -295,4 +303,20 @@
         mAnimations.add(va);
         mTransitions.getAnimExecutor().execute(va::start);
     }
+
+    /** Bundled information of dismiss transition. */
+    static class DismissTransition {
+        IBinder mTransition;
+
+        int mReason;
+
+        @SplitScreen.StageType
+        int mDismissTop;
+
+        DismissTransition(IBinder transition, int reason, int dismissTop) {
+            this.mTransition = transition;
+            this.mReason = reason;
+            this.mDismissTop = dismissTop;
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 5e8f29f..43a1d74b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -18,9 +18,10 @@
 
 import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.view.WindowManager.transitTypeToString;
@@ -32,7 +33,6 @@
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
-import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
@@ -40,6 +40,7 @@
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_UNKNOWN;
 import static com.android.wm.shell.splitscreen.SplitScreenController.exitReasonToString;
 import static com.android.wm.shell.splitscreen.SplitScreenTransitions.FLAG_IS_DIVIDER_BAR;
 import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -121,9 +122,6 @@
 
     private static final String TAG = StageCoordinator.class.getSimpleName();
 
-    /** internal value for mDismissTop that represents no dismiss */
-    private static final int NO_DISMISS = -2;
-
     private final SurfaceSession mSurfaceSession = new SurfaceSession();
 
     private final MainStage mMainStage;
@@ -156,9 +154,6 @@
     private boolean mKeyguardOccluded;
     private boolean mDeviceSleep;
 
-    @StageType
-    private int mDismissTop = NO_DISMISS;
-
     /** The target stage to dismiss to when unlock after folded. */
     @StageType
     private int mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
@@ -171,7 +166,6 @@
             setDividerVisibility(false);
             mSplitLayout.resetDividerPosition();
         }
-        mDismissTop = NO_DISMISS;
     };
 
     private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks =
@@ -461,8 +455,8 @@
                         options = resolveStartStage(STAGE_TYPE_SIDE, position, options, wct);
                     }
                 } else {
-                    // Exit split-screen and launch fullscreen since stage wasn't specified.
-                    prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
+                    Slog.w(TAG,
+                            "No stage type nor split position specified to resolve start stage");
                 }
                 break;
             }
@@ -914,23 +908,22 @@
         }
     }
 
-    @VisibleForTesting
-    IBinder onSnappedToDismissTransition(boolean mainStageToTop) {
-        final WindowContainerTransaction wct = new WindowContainerTransaction();
-        prepareExitSplitScreen(mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE, wct);
-        return mSplitTransitions.startSnapToDismiss(wct, this);
-    }
-
     @Override
     public void onSnappedToDismiss(boolean bottomOrRight) {
         final boolean mainStageToTop =
                 bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
                         : mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
-        if (ENABLE_SHELL_TRANSITIONS) {
-            onSnappedToDismissTransition(mainStageToTop);
+
+        if (!ENABLE_SHELL_TRANSITIONS) {
+            exitSplitScreen(mainStageToTop ? mMainStage : mSideStage, EXIT_REASON_DRAG_DIVIDER);
             return;
         }
-        exitSplitScreen(mainStageToTop ? mMainStage : mSideStage, EXIT_REASON_DRAG_DIVIDER);
+
+        final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        prepareExitSplitScreen(dismissTop, wct);
+        mSplitTransitions.startDismissTransition(
+                null /* transition */, wct, this, dismissTop, EXIT_REASON_DRAG_DIVIDER);
     }
 
     @Override
@@ -1109,14 +1102,25 @@
             @Nullable TransitionRequestInfo request) {
         final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
         if (triggerTask == null) {
-            // still want to monitor everything while in split-screen, so return non-null.
+            // Still want to monitor everything while in split-screen, so return non-null.
             return isSplitScreenVisible() ? new WindowContainerTransaction() : null;
+        } else if (triggerTask.displayId != mDisplayId) {
+            // Skip handling task on the other display.
+            return null;
         }
 
         WindowContainerTransaction out = null;
         final @WindowManager.TransitionType int type = request.getType();
+        final boolean isOpening = isOpeningType(type);
+        final boolean inFullscreen = triggerTask.getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
+
+        if (isOpening && inFullscreen) {
+            // One task is opening into fullscreen mode, remove the corresponding split record.
+            mRecentTasks.ifPresent(recentTasks -> recentTasks.removeSplitPair(triggerTask.taskId));
+        }
+
         if (isSplitScreenVisible()) {
-            // try to handle everything while in split-screen, so return a WCT even if it's empty.
+            // Try to handle everything while in split-screen, so return a WCT even if it's empty.
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  split is active so using split"
                             + "Transition to handle request. triggerTask=%d type=%s mainChildren=%d"
                             + " sideChildren=%d", triggerTask.taskId, transitTypeToString(type),
@@ -1124,35 +1128,35 @@
             out = new WindowContainerTransaction();
             final StageTaskListener stage = getStageOfTask(triggerTask);
             if (stage != null) {
-                // dismiss split if the last task in one of the stages is going away
+                // Dismiss split if the last task in one of the stages is going away
                 if (isClosingType(type) && stage.getChildCount() == 1) {
                     // The top should be the opposite side that is closing:
-                    mDismissTop = getStageType(stage) == STAGE_TYPE_MAIN
-                            ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
+                    int dismissTop = getStageType(stage) == STAGE_TYPE_MAIN ? STAGE_TYPE_SIDE
+                            : STAGE_TYPE_MAIN;
+                    prepareExitSplitScreen(dismissTop, out);
+                    mSplitTransitions.startDismissTransition(transition, out, this, dismissTop,
+                            EXIT_REASON_APP_FINISHED);
                 }
-            } else {
-                if (triggerTask.getActivityType() == ACTIVITY_TYPE_HOME && isOpeningType(type)) {
-                    // Going home so dismiss both.
-                    mDismissTop = STAGE_TYPE_UNDEFINED;
+            } else if (isOpening && inFullscreen) {
+                final int activityType = triggerTask.getActivityType();
+                if (activityType == ACTIVITY_TYPE_ASSISTANT) {
+                    // We don't want assistant panel to dismiss split screen, so do nothing.
+                } else {
+                    // Going home or occluded by the other fullscreen task, so dismiss both.
+                    prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
+                    final int exitReason = activityType == ACTIVITY_TYPE_HOME
+                            ? EXIT_REASON_RETURN_HOME : EXIT_REASON_UNKNOWN;
+                    mSplitTransitions.startDismissTransition(transition, out, this,
+                            STAGE_TYPE_UNDEFINED, exitReason);
                 }
             }
-            if (mDismissTop != NO_DISMISS) {
-                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
-                                + " deduced Dismiss from request. toTop=%s",
-                        stageTypeToString(mDismissTop));
-                prepareExitSplitScreen(mDismissTop, out);
-                mSplitTransitions.mPendingDismiss = transition;
-            }
         } else {
-            // Not in split mode, so look for an open into a split stage to active split screen.
-            if ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)) {
-                if (getStageOfTask(triggerTask) != null) {
-                    // One task is appearing in split, prepare to enter split screen.
-                    out = new WindowContainerTransaction();
-                    mSplitTransitions.mPendingEnter = transition;
-                    mMainStage.activate(getMainStageBounds(), out, true /* includingTopTask */);
-                    mSideStage.moveToTop(getSideStageBounds(), out);
-                }
+            if (isOpening && getStageOfTask(triggerTask) != null) {
+                // One task is appearing into split, prepare to enter split screen.
+                out = new WindowContainerTransaction();
+                mMainStage.activate(getMainStageBounds(), out, true /* includingTopTask */);
+                mSideStage.moveToTop(getSideStageBounds(), out);
+                mSplitTransitions.mPendingEnter = transition;
             }
         }
         return out;
@@ -1164,8 +1168,9 @@
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
-        if (transition != mSplitTransitions.mPendingDismiss
-                && transition != mSplitTransitions.mPendingEnter) {
+        if (transition != mSplitTransitions.mPendingEnter && (
+                mSplitTransitions.mPendingDismiss == null
+                        || mSplitTransitions.mPendingDismiss.mTransition != transition)) {
             // Not entering or exiting, so just do some house-keeping and validation.
 
             // If we're not in split-mode, just abort so something else can handle it.
@@ -1208,8 +1213,10 @@
         boolean shouldAnimate = true;
         if (mSplitTransitions.mPendingEnter == transition) {
             shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
-        } else if (mSplitTransitions.mPendingDismiss == transition) {
-            shouldAnimate = startPendingDismissAnimation(transition, info, startTransaction);
+        } else if (mSplitTransitions.mPendingDismiss != null
+                && mSplitTransitions.mPendingDismiss.mTransition == transition) {
+            shouldAnimate = startPendingDismissAnimation(
+                    mSplitTransitions.mPendingDismiss, info, startTransaction);
         }
         if (!shouldAnimate) return false;
 
@@ -1263,10 +1270,22 @@
                     + " to have been called with " + sideChild.getTaskInfo().taskId
                     + " before startAnimation().");
         }
+
+        mShouldUpdateRecents = true;
+        updateRecentTasksSplitPair();
+
+        if (!mLogger.hasStartedSession()) {
+            mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
+                    getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+                    getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+                    mSplitLayout.isLandscape());
+        }
+
         return true;
     }
 
-    private boolean startPendingDismissAnimation(@NonNull IBinder transition,
+    private boolean startPendingDismissAnimation(
+            @NonNull SplitScreenTransitions.DismissTransition dismissTransition,
             @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
         // Make some noise if things aren't totally expected. These states shouldn't effect
         // transitions locally, but remotes (like Launcher) may get confused if they were
@@ -1295,6 +1314,21 @@
                     + "] before startAnimation().");
         }
 
+        mRecentTasks.ifPresent(recentTasks -> {
+            // Notify recents if we are exiting in a way that breaks the pair, and disable further
+            // updates to splits in the recents until we enter split again
+            if (shouldBreakPairedTaskInRecents(dismissTransition.mReason) && mShouldUpdateRecents) {
+                for (TransitionInfo.Change change : info.getChanges()) {
+                    final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+                    if (taskInfo != null
+                            && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+                        recentTasks.removeSplitPair(taskInfo.taskId);
+                    }
+                }
+            }
+        });
+        mShouldUpdateRecents = false;
+
         // Update local states.
         setSplitsVisible(false);
         // Wait until after animation to update divider
@@ -1305,15 +1339,17 @@
             t.setWindowCrop(mSideStage.mRootLeash, null);
         }
 
-        if (mDismissTop == STAGE_TYPE_UNDEFINED) {
-            // Going home (dismissing both splits)
-
+        if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
+            logExit(dismissTransition.mReason);
             // TODO: Have a proper remote for this. Until then, though, reset state and use the
             //       normal animation stuff (which falls back to the normal launcher remote).
             t.hide(mSplitLayout.getDividerLeash());
             setDividerVisibility(false);
             mSplitTransitions.mPendingDismiss = null;
             return false;
+        } else {
+            logExitToStage(dismissTransition.mReason,
+                    dismissTransition.mDismissTop == STAGE_TYPE_MAIN);
         }
 
         addDividerBarToTransition(info, t, false /* show */);
@@ -1457,7 +1493,15 @@
         @Override
         public void onNoLongerSupportMultiWindow() {
             if (mMainStage.isActive()) {
-                StageCoordinator.this.exitSplitScreen(null /* childrenToTop */,
+                if (!ENABLE_SHELL_TRANSITIONS) {
+                    StageCoordinator.this.exitSplitScreen(null /* childrenToTop */,
+                            EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
+                }
+
+                final WindowContainerTransaction wct = new WindowContainerTransaction();
+                prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
+                mSplitTransitions.startDismissTransition(null /* transition */, wct,
+                        StageCoordinator.this, STAGE_TYPE_UNDEFINED,
                         EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
             }
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenTransitions.java
index af9a5aa..0183654 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/SplitScreenTransitions.java
@@ -127,12 +127,6 @@
                 }
                 // TODO(shell-transitions): screenshot here
                 final Rect startBounds = new Rect(change.getStartAbsBounds());
-                if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
-                    // Dismissing split via snap which means the still-visible task has been
-                    // dragged to its end position at animation start so reflect that here.
-                    startBounds.offsetTo(change.getEndAbsBounds().left,
-                            change.getEndAbsBounds().top);
-                }
                 final Rect endBounds = new Rect(change.getEndAbsBounds());
                 startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
                 endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index a7a1788..b8cbfd9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -89,6 +89,9 @@
     /** Transition type for entering split by opening an app into side-stage. */
     public static final int TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE = TRANSIT_FIRST_CUSTOM + 5;
 
+    /** Transition type for dismissing split-screen. */
+    public static final int TRANSIT_SPLIT_DISMISS = TRANSIT_FIRST_CUSTOM + 6;
+
     private final WindowOrganizer mOrganizer;
     private final Context mContext;
     private final ShellExecutor mMainExecutor;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
index 2b5cd60..51eec27 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -36,6 +37,7 @@
     private WindowContainerToken mToken = createMockWCToken();
     private int mParentTaskId = INVALID_TASK_ID;
     private @WindowConfiguration.ActivityType int mActivityType = ACTIVITY_TYPE_STANDARD;
+    private @WindowConfiguration.WindowingMode int mWindowingMode = WINDOWING_MODE_UNDEFINED;
 
     public static WindowContainerToken createMockWCToken() {
         final IWindowContainerToken itoken = mock(IWindowContainerToken.class);
@@ -60,6 +62,12 @@
         return this;
     }
 
+    public TestRunningTaskInfoBuilder setWindowingMode(
+            @WindowConfiguration.WindowingMode int windowingMode) {
+        mWindowingMode = windowingMode;
+        return this;
+    }
+
     public ActivityManager.RunningTaskInfo build() {
         final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
         info.parentTaskId = INVALID_TASK_ID;
@@ -67,6 +75,7 @@
         info.parentTaskId = mParentTaskId;
         info.configuration.windowConfiguration.setBounds(mBounds);
         info.configuration.windowConfiguration.setActivityType(mActivityType);
+        info.configuration.windowConfiguration.setWindowingMode(mWindowingMode);
         info.token = mToken;
         info.isResizeable = true;
         info.supportsMultiWindow = true;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index c853fd3..be1ef09 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -17,6 +17,7 @@
 package com.android.wm.shell.splitscreen;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -26,6 +27,9 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 
+import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
+import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
 import static com.android.wm.shell.splitscreen.SplitTestUtils.createMockSurface;
 import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
 
@@ -249,7 +253,9 @@
         enterSplit();
 
         ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder()
-                .setActivityType(ACTIVITY_TYPE_HOME).build();
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+                .setActivityType(ACTIVITY_TYPE_HOME)
+                .build();
 
         // Create a request to bring home forward
         TransitionRequestInfo request = new TransitionRequestInfo(TRANSIT_TO_FRONT, homeTask, null);
@@ -280,6 +286,64 @@
     }
 
     @Test
+    public void testDismissFromBeingOccluded() {
+        enterSplit();
+
+        ActivityManager.RunningTaskInfo normalTask = new TestRunningTaskInfoBuilder()
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
+                .build();
+
+        // Create a request to bring a normal task forward
+        TransitionRequestInfo request =
+                new TransitionRequestInfo(TRANSIT_TO_FRONT, normalTask, null);
+        IBinder transition = mock(IBinder.class);
+        WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request);
+
+        assertTrue(containsSplitExit(result));
+
+        // make sure we haven't made any local changes yet (need to wait until transition is ready)
+        assertTrue(mStageCoordinator.isSplitScreenVisible());
+
+        // simulate the transition
+        TransitionInfo.Change normalChange = createChange(TRANSIT_TO_FRONT, normalTask);
+        TransitionInfo.Change mainChange = createChange(TRANSIT_TO_BACK, mMainChild);
+        TransitionInfo.Change sideChange = createChange(TRANSIT_TO_BACK, mSideChild);
+
+        TransitionInfo info = new TransitionInfo(TRANSIT_TO_FRONT, 0);
+        info.addChange(normalChange);
+        info.addChange(mainChange);
+        info.addChange(sideChange);
+        mMainStage.onTaskVanished(mMainChild);
+        mSideStage.onTaskVanished(mSideChild);
+        mStageCoordinator.startAnimation(transition, info,
+                mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
+                mock(Transitions.TransitionFinishCallback.class));
+        assertFalse(mStageCoordinator.isSplitScreenVisible());
+    }
+
+    @Test
+    public void testDismissFromMultiWindowSupport() {
+        enterSplit();
+
+        // simulate the transition
+        TransitionInfo.Change mainChange = createChange(TRANSIT_TO_BACK, mMainChild);
+        TransitionInfo.Change sideChange = createChange(TRANSIT_TO_BACK, mSideChild);
+        TransitionInfo info = new TransitionInfo(TRANSIT_TO_BACK, 0);
+        info.addChange(mainChange);
+        info.addChange(sideChange);
+        IBinder transition = mSplitScreenTransitions.startDismissTransition(null,
+                new WindowContainerTransaction(), mStageCoordinator,
+                EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW, STAGE_TYPE_SIDE);
+        boolean accepted = mStageCoordinator.startAnimation(transition, info,
+                mock(SurfaceControl.Transaction.class),
+                mock(SurfaceControl.Transaction.class),
+                mock(Transitions.TransitionFinishCallback.class));
+        assertTrue(accepted);
+        assertFalse(mStageCoordinator.isSplitScreenVisible());
+    }
+
+    @Test
     public void testDismissSnap() {
         enterSplit();
 
@@ -290,8 +354,9 @@
         TransitionInfo info = new TransitionInfo(TRANSIT_TO_BACK, 0);
         info.addChange(mainChange);
         info.addChange(sideChange);
-        IBinder transition = mStageCoordinator.onSnappedToDismissTransition(
-                false /* mainStageToTop */);
+        IBinder transition = mSplitScreenTransitions.startDismissTransition(null,
+                new WindowContainerTransaction(), mStageCoordinator, EXIT_REASON_DRAG_DIVIDER,
+                STAGE_TYPE_SIDE);
         mMainStage.onTaskVanished(mMainChild);
         mSideStage.onTaskVanished(mSideChild);
         boolean accepted = mStageCoordinator.startAnimation(transition, info,
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 2f8ddee..02257db 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -262,8 +262,6 @@
                         0,
                         EGL_DEPTH_SIZE,
                         0,
-                        EGL_STENCIL_SIZE,
-                        STENCIL_BUFFER_SIZE,
                         EGL_SURFACE_TYPE,
                         EGL_WINDOW_BIT | eglSwapBehavior,
                         EGL_NONE};
@@ -354,10 +352,6 @@
         ALOGW("Failed to initialize 101010-2 format, error = %s",
               eglErrorString());
     }
-    mEglConfigA8 = loadA8Config(mEglDisplay, mSwapBehavior);
-    if (mEglConfigA8 == EGL_NO_CONFIG_KHR) {
-        ALOGE("Failed to initialize A8 format, error = %s", eglErrorString());
-    }
 }
 
 void EglManager::createContext() {
@@ -431,9 +425,13 @@
     EGLConfig config = mEglConfig;
     if (colorMode == ColorMode::A8) {
         // A8 doesn't use a color space
+        if (!mEglConfigA8) {
+            mEglConfigA8 = loadA8Config(mEglDisplay, mSwapBehavior);
+            LOG_ALWAYS_FATAL_IF(!mEglConfigA8,
+                                "Requested ColorMode::A8, but EGL lacks support! error = %s",
+                                eglErrorString());
+        }
         config = mEglConfigA8;
-
-        LOG_ALWAYS_FATAL_IF(!mEglConfigA8, "Requested ColorMode::A8, but EGL lacks support!");
     } else {
         if (!mHasWideColorGamutSupport) {
             colorMode = ColorMode::Default;
diff --git a/media/java/android/media/tv/interactive/ITvIAppClient.aidl b/media/java/android/media/tv/interactive/ITvIAppClient.aidl
index 30ef503..a5f2331 100644
--- a/media/java/android/media/tv/interactive/ITvIAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppClient.aidl
@@ -15,9 +15,9 @@
  */
 
 package android.media.tv.interactive;
-import android.media.tv.BroadcastInfoRequest;
 
 import android.media.tv.BroadcastInfoRequest;
+import android.os.Bundle;
 import android.view.InputChannel;
 
 /**
@@ -31,4 +31,5 @@
     void onLayoutSurface(int left, int top, int right, int bottom, int seq);
     void onBroadcastInfoRequest(in BroadcastInfoRequest request, int seq);
     void onSessionStateChanged(int state, int seq);
-}
\ No newline at end of file
+    void onCommandRequest(in String cmdType, in Bundle parameters, int seq);
+}
diff --git a/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl
index ff8af88..66f5fc1 100644
--- a/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppSessionCallback.aidl
@@ -19,6 +19,7 @@
 import android.media.tv.BroadcastInfoRequest;
 import android.media.tv.interactive.ITvIAppSession;
 import android.media.tv.BroadcastInfoRequest;
+import android.os.Bundle;
 
 /**
  * Helper interface for ITvIAppSession to allow TvIAppService to notify the system service when
@@ -30,4 +31,5 @@
     void onLayoutSurface(int left, int top, int right, int bottom);
     void onBroadcastInfoRequest(in BroadcastInfoRequest request);
     void onSessionStateChanged(int state);
-}
\ No newline at end of file
+    void onCommandRequest(in String cmdType, in Bundle parameters);
+}
diff --git a/media/java/android/media/tv/interactive/TvIAppManager.java b/media/java/android/media/tv/interactive/TvIAppManager.java
index a232e31..9390d8d 100644
--- a/media/java/android/media/tv/interactive/TvIAppManager.java
+++ b/media/java/android/media/tv/interactive/TvIAppManager.java
@@ -244,6 +244,19 @@
             }
 
             @Override
+            public void onCommandRequest(@TvIAppService.IAppServiceCommandType String cmdType,
+                    Bundle parameters, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postCommandRequest(cmdType, parameters);
+                }
+            }
+
+            @Override
             public void onSessionStateChanged(int state, int seq) {
                 synchronized (mSessionCallbackRecordMap) {
                     SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -1046,6 +1059,16 @@
             });
         }
 
+        void postCommandRequest(final @TvIAppService.IAppServiceCommandType String cmdType,
+                final Bundle parameters) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onCommandRequest(mSession, cmdType, parameters);
+                }
+            });
+        }
+
         void postSessionStateChanged(int state) {
             mHandler.post(new Runnable() {
                 @Override
@@ -1093,6 +1116,17 @@
         }
 
         /**
+         * This is called when {@link TvIAppService.Session#requestCommand} is called.
+         *
+         * @param session A {@link TvIAppManager.Session} associated with this callback.
+         * @param cmdType type of the command.
+         * @param parameters parameters of the command.
+         */
+        public void onCommandRequest(Session session,
+                @TvIAppService.IAppServiceCommandType String cmdType, Bundle parameters) {
+        }
+
+        /**
          * This is called when {@link TvIAppService.Session#notifySessionStateChanged} is called.
          *
          * @param session A {@link TvIAppManager.Session} associated with this callback.
diff --git a/media/java/android/media/tv/interactive/TvIAppService.java b/media/java/android/media/tv/interactive/TvIAppService.java
index 1e11baf..6475f90 100644
--- a/media/java/android/media/tv/interactive/TvIAppService.java
+++ b/media/java/android/media/tv/interactive/TvIAppService.java
@@ -19,6 +19,7 @@
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringDef;
 import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.Service;
@@ -53,6 +54,8 @@
 
 import com.android.internal.os.SomeArgs;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -83,6 +86,28 @@
      */
     public static final String SERVICE_META_DATA = "android.media.tv.interactive.app";
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef(prefix = "IAPP_SERVICE_COMMAND_TYPE_", value = {
+            IAPP_SERVICE_COMMAND_TYPE_TUNE,
+            IAPP_SERVICE_COMMAND_TYPE_TUNENEXT,
+            IAPP_SERVICE_COMMAND_TYPE_TUNEPREV,
+            IAPP_SERVICE_COMMAND_TYPE_STOP,
+            IAPP_SERVICE_COMMAND_TYPE_SETSTREAMVOLUME
+    })
+    public @interface IAppServiceCommandType {}
+
+    /** @hide */
+    public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE = "Tune";
+    /** @hide */
+    public static final String IAPP_SERVICE_COMMAND_TYPE_TUNENEXT = "TuneNext";
+    /** @hide */
+    public static final String IAPP_SERVICE_COMMAND_TYPE_TUNEPREV = "TunePrevious";
+    /** @hide */
+    public static final String IAPP_SERVICE_COMMAND_TYPE_STOP = "Stop";
+    /** @hide */
+    public static final String IAPP_SERVICE_COMMAND_TYPE_SETSTREAMVOLUME = "setStreamVolume";
+
     private final Handler mServiceHandler = new ServiceHandler();
     private final RemoteCallbackList<ITvIAppServiceCallback> mCallbacks =
             new RemoteCallbackList<>();
@@ -443,6 +468,31 @@
             });
         }
 
+        /**
+         * requests a specific command to be processed by the related TV input.
+         * @param cmdType type of the specific command
+         * @param parameters parameters of the specific command
+         */
+        public void requestCommand(@IAppServiceCommandType String cmdType, Bundle parameters) {
+            executeOrPostRunnableOnMainThread(new Runnable() {
+                @MainThread
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) {
+                            Log.d(TAG, "requestCommand (cmdType=" + cmdType + ", parameters="
+                                    + parameters.toString() + ")");
+                        }
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onCommandRequest(cmdType, parameters);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in requestCommand", e);
+                    }
+                }
+            });
+        }
+
         void startIApp() {
             onStartIApp();
         }
diff --git a/media/java/android/media/tv/interactive/TvIAppView.java b/media/java/android/media/tv/interactive/TvIAppView.java
index 8031981..efbe9e3 100644
--- a/media/java/android/media/tv/interactive/TvIAppView.java
+++ b/media/java/android/media/tv/interactive/TvIAppView.java
@@ -26,6 +26,7 @@
 import android.media.tv.TvView;
 import android.media.tv.interactive.TvIAppManager.Session;
 import android.media.tv.interactive.TvIAppManager.SessionCallback;
+import android.os.Bundle;
 import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -53,6 +54,7 @@
     private final Handler mHandler = new Handler();
     private Session mSession;
     private MySessionCallback mSessionCallback;
+    private TvIAppCallback mCallback;
     private SurfaceView mSurfaceView;
     private Surface mSurface;
 
@@ -123,6 +125,16 @@
         mTvIAppManager = (TvIAppManager) getContext().getSystemService("tv_interactive_app");
     }
 
+    /**
+     * Sets the callback to be invoked when an event is dispatched to this TvIAppView.
+     *
+     * @param callback The callback to receive events. A value of {@code null} removes the existing
+     *            callback.
+     */
+    public void setCallback(@Nullable TvIAppCallback callback) {
+        mCallback = callback;
+    }
+
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
@@ -322,6 +334,23 @@
         return UNSET_TVVIEW_SUCCESS;
     }
 
+    /**
+     * Callback used to receive various status updates on the {@link TvIAppView}.
+     */
+    public abstract static class TvIAppCallback {
+
+        /**
+         * This is called when a command is requested to be processed by the related TV input.
+         *
+         * @param iAppServiceId The ID of the TV interactive app service bound to this view.
+         * @param cmdType type of the command
+         * @param parameters parameters of the command
+         */
+        public void onCommandRequest(String iAppServiceId,
+                @TvIAppService.IAppServiceCommandType String cmdType, Bundle parameters) {
+        }
+    }
+
     private class MySessionCallback extends SessionCallback {
         final String mIAppServiceId;
         int mType;
@@ -395,5 +424,21 @@
             mUseRequestedSurfaceLayout = true;
             requestLayout();
         }
+
+        @Override
+        public void onCommandRequest(Session session,
+                @TvIAppService.IAppServiceCommandType String cmdType, Bundle parameters) {
+            if (DEBUG) {
+                Log.d(TAG, "onCommandRequest (cmdType=" + cmdType + ", parameters="
+                        + parameters.toString() + ")");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onCommandRequest - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onCommandRequest(mIAppServiceId, cmdType, parameters);
+            }
+        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index f0f576e..5d71a13 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -159,7 +159,8 @@
     public @interface Status {}
 
     /**
-     * The status of a filter that the data in the filter buffer is ready to be read.
+     * The status of a filter that the data in the filter buffer is ready to be read. It can also be
+     * used to know the STC (System Time Clock) ready status if it's PCR filter.
      */
     public static final int STATUS_DATA_READY = DemuxFilterStatus.DATA_READY;
     /**
diff --git a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
index 58a81d9..c8bb178 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
@@ -55,7 +55,7 @@
     }
 
     /**
-     * Gets data size in bytes of filtered data.
+     * Gets the record data offset from the beginning of the record buffer.
      */
     @BytesLong
     public long getDataLength() {
diff --git a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
index bf2c000..12ea2224 100644
--- a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
@@ -71,7 +71,7 @@
     }
 
     /**
-     * Gets data size in bytes of filtered data.
+     * Gets the record data offset from the beginning of the record buffer.
      */
     @BytesLong
     public long getDataLength() {
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 582e4f5..0527a1a 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -645,6 +645,8 @@
     }
     /**
      * Gets the current Automatic Gain Control value which is normalized from 0 to 255.
+     *
+     * Larger AGC values indicate it is applying more gain.
      */
     public int getAgc() {
         if (mAgc == null) {
@@ -663,6 +665,10 @@
     }
     /**
      * Gets the current Error information by layer.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, vec[0] is the information of
+     * layer A. vec[1] is the information of layer B.
      */
     @NonNull
     public boolean[] getLayerErrors() {
@@ -736,6 +742,10 @@
      *
      * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, vec[0] is the information of
+     * layer A. vec[1] is the information of layer B.
      */
     @NonNull
     public int[] getBers() {
@@ -752,6 +762,10 @@
      *
      * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, vec[0] is the information of
+     * layer A. vec[1] is the information of layer B.
      */
     @NonNull
     @FrontendSettings.InnerFec
@@ -849,6 +863,10 @@
      *
      * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, vec[0] is the information of
+     * layer A. vec[1] is the information of layer B.
      */
     @NonNull
     @FrontendInterleaveMode
@@ -867,6 +885,10 @@
      *
      * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, vec[0] is the information of
+     * layer A. vec[1] is the information of layer B.
      */
     @NonNull
     @IntRange(from = 0, to = 0xff)
@@ -900,6 +922,10 @@
      *
      * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * The order of the vectors is in ascending order of the required CNR (Contrast-to-noise ratio).
+     * The most robust layer is the first. For example, in ISDB-T, vec[0] is the information of
+     * layer A. vec[1] is the information of layer B.
      */
     @NonNull
     @FrontendModulation
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index f61bd52..cb35edb 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -28,7 +28,12 @@
 @SystemApi
 public interface ScanCallback {
 
-    /** Scan locked the signal. */
+    /**
+     * Scan locked the signal.
+     *
+     * It can also be notified after signal is locked if the signal attributes transmission
+     * parameter of the signal is changed (e.g., Modulation).
+     */
     void onLocked();
 
     /** Scan stopped. */
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index 8a6c85d..ca83309 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -45,8 +45,6 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.DataUnit;
@@ -135,15 +133,6 @@
 
     private int mFlags;
 
-    /**
-     * {@hide}
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public NetworkStatsManager(Context context) throws ServiceNotFoundException {
-        this(context, INetworkStatsService.Stub.asInterface(
-                ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)));
-    }
-
     /** @hide */
     @VisibleForTesting
     public NetworkStatsManager(Context context, INetworkStatsService service) {
diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
index f251b86..d1e432e 100644
--- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
@@ -45,7 +45,6 @@
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.TrafficStats;
-import android.net.util.NetdService;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
@@ -96,8 +95,6 @@
 public class IpSecService extends IIpSecService.Stub {
     private static final String TAG = "IpSecService";
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private static final String NETD_SERVICE_NAME = "netd";
     private static final int[] ADDRESS_FAMILIES =
             new int[] {OsConstants.AF_INET, OsConstants.AF_INET6};
 
@@ -106,6 +103,8 @@
 
     @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10;
 
+    private final INetd mNetd;
+
     static {
         try {
             INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
@@ -627,16 +626,14 @@
         public void freeUnderlyingResources() {
             int spi = mSpi.getSpi();
             try {
-                mDeps
-                        .getNetdInstance(mContext)
-                        .ipSecDeleteSecurityAssociation(
-                                mUid,
-                                mConfig.getSourceAddress(),
-                                mConfig.getDestinationAddress(),
-                                spi,
-                                mConfig.getMarkValue(),
-                                mConfig.getMarkMask(),
-                                mConfig.getXfrmInterfaceId());
+                mNetd.ipSecDeleteSecurityAssociation(
+                        mUid,
+                        mConfig.getSourceAddress(),
+                        mConfig.getDestinationAddress(),
+                        spi,
+                        mConfig.getMarkValue(),
+                        mConfig.getMarkMask(),
+                        mConfig.getXfrmInterfaceId());
             } catch (RemoteException | ServiceSpecificException e) {
                 Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e);
             }
@@ -680,14 +677,12 @@
         private final String mSourceAddress;
         private final String mDestinationAddress;
         private int mSpi;
-        private final Context mContext;
 
         private boolean mOwnedByTransform = false;
 
-        SpiRecord(Context context, int resourceId, String sourceAddress,
+        SpiRecord(int resourceId, String sourceAddress,
                 String destinationAddress, int spi) {
             super(resourceId);
-            mContext = context;
             mSourceAddress = sourceAddress;
             mDestinationAddress = destinationAddress;
             mSpi = spi;
@@ -698,11 +693,9 @@
         public void freeUnderlyingResources() {
             try {
                 if (!mOwnedByTransform) {
-                    mDeps
-                            .getNetdInstance(mContext)
-                            .ipSecDeleteSecurityAssociation(
-                                    mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */,
-                                    0 /* mask */, 0 /* if_id */);
+                    mNetd.ipSecDeleteSecurityAssociation(
+                            mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */,
+                            0 /* mask */, 0 /* if_id */);
                 }
             } catch (ServiceSpecificException | RemoteException e) {
                 Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
@@ -821,10 +814,8 @@
         private final int mIfId;
 
         private Network mUnderlyingNetwork;
-        private final Context mContext;
 
         TunnelInterfaceRecord(
-                Context context,
                 int resourceId,
                 String interfaceName,
                 Network underlyingNetwork,
@@ -835,7 +826,6 @@
                 int intfId) {
             super(resourceId);
 
-            mContext = context;
             mInterfaceName = interfaceName;
             mUnderlyingNetwork = underlyingNetwork;
             mLocalAddress = localAddr;
@@ -852,18 +842,17 @@
             //       Teardown VTI
             //       Delete global policies
             try {
-                final INetd netd = mDeps.getNetdInstance(mContext);
-                netd.ipSecRemoveTunnelInterface(mInterfaceName);
+                mNetd.ipSecRemoveTunnelInterface(mInterfaceName);
 
                 for (int selAddrFamily : ADDRESS_FAMILIES) {
-                    netd.ipSecDeleteSecurityPolicy(
+                    mNetd.ipSecDeleteSecurityPolicy(
                             mUid,
                             selAddrFamily,
                             IpSecManager.DIRECTION_OUT,
                             mOkey,
                             0xffffffff,
                             mIfId);
-                    netd.ipSecDeleteSecurityPolicy(
+                    mNetd.ipSecDeleteSecurityPolicy(
                             mUid,
                             selAddrFamily,
                             IpSecManager.DIRECTION_IN,
@@ -1026,7 +1015,6 @@
     static IpSecService create(Context context)
             throws InterruptedException {
         final IpSecService service = new IpSecService(context);
-        service.connectNativeNetdService();
         return service;
     }
 
@@ -1057,8 +1045,13 @@
     @VisibleForTesting
     public IpSecService(Context context, Dependencies deps, UidFdTagger uidFdTagger) {
         mContext = context;
-        mDeps = deps;
+        mDeps = Objects.requireNonNull(deps, "Missing dependencies.");
         mUidFdTagger = uidFdTagger;
+        try {
+            mNetd = mDeps.getNetdInstance(mContext);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /** Called by system server when system is ready. */
@@ -1070,25 +1063,12 @@
         }
     }
 
-    private void connectNativeNetdService() {
-        // Avoid blocking the system server to do this
-        new Thread() {
-            @Override
-            public void run() {
-                synchronized (IpSecService.this) {
-                    NetdService.get(NETD_FETCH_TIMEOUT_MS);
-                }
-            }
-        }.start();
-    }
-
     synchronized boolean isNetdAlive() {
         try {
-            final INetd netd = mDeps.getNetdInstance(mContext);
-            if (netd == null) {
+            if (mNetd == null) {
                 return false;
             }
-            return netd.isAlive();
+            return mNetd.isAlive();
         } catch (RemoteException re) {
             return false;
         }
@@ -1149,15 +1129,12 @@
                         IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi);
             }
 
-            spi =
-                    mDeps
-                            .getNetdInstance(mContext)
-                            .ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi);
+            spi = mNetd.ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi);
             Log.d(TAG, "Allocated SPI " + spi);
             userRecord.mSpiRecords.put(
                     resourceId,
                     new RefcountedResource<SpiRecord>(
-                            new SpiRecord(mContext, resourceId, "",
+                            new SpiRecord(resourceId, "",
                             destinationAddress, spi), binder));
         } catch (ServiceSpecificException e) {
             if (e.errorCode == OsConstants.ENOENT) {
@@ -1275,8 +1252,7 @@
                     OsConstants.UDP_ENCAP,
                     OsConstants.UDP_ENCAP_ESPINUDP);
 
-            mDeps.getNetdInstance(mContext).ipSecSetEncapSocketOwner(
-                        new ParcelFileDescriptor(sockFd), callingUid);
+            mNetd.ipSecSetEncapSocketOwner(new ParcelFileDescriptor(sockFd), callingUid);
             if (port != 0) {
                 Log.v(TAG, "Binding to port " + port);
                 Os.bind(sockFd, INADDR_ANY, port);
@@ -1338,16 +1314,15 @@
             //       Create VTI
             //       Add inbound/outbound global policies
             //              (use reqid = 0)
-            final INetd netd = mDeps.getNetdInstance(mContext);
-            netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId);
+            mNetd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId);
 
             BinderUtils.withCleanCallingIdentity(() -> {
-                NetdUtils.setInterfaceUp(netd, intfName);
+                NetdUtils.setInterfaceUp(mNetd, intfName);
             });
 
             for (int selAddrFamily : ADDRESS_FAMILIES) {
                 // Always send down correct local/remote addresses for template.
-                netd.ipSecAddSecurityPolicy(
+                mNetd.ipSecAddSecurityPolicy(
                         callerUid,
                         selAddrFamily,
                         IpSecManager.DIRECTION_OUT,
@@ -1357,7 +1332,7 @@
                         okey,
                         0xffffffff,
                         resourceId);
-                netd.ipSecAddSecurityPolicy(
+                mNetd.ipSecAddSecurityPolicy(
                         callerUid,
                         selAddrFamily,
                         IpSecManager.DIRECTION_IN,
@@ -1377,7 +1352,7 @@
                 //
                 // This is necessary only on the tunnel interface, and not any the interface to
                 // which traffic will be forwarded to.
-                netd.ipSecAddSecurityPolicy(
+                mNetd.ipSecAddSecurityPolicy(
                         callerUid,
                         selAddrFamily,
                         IpSecManager.DIRECTION_FWD,
@@ -1393,7 +1368,6 @@
                     resourceId,
                     new RefcountedResource<TunnelInterfaceRecord>(
                             new TunnelInterfaceRecord(
-                                    mContext,
                                     resourceId,
                                     intfName,
                                     underlyingNetwork,
@@ -1435,12 +1409,10 @@
         try {
             // We can assume general validity of the IP address, since we get them as a
             // LinkAddress, which does some validation.
-            mDeps
-                    .getNetdInstance(mContext)
-                    .interfaceAddAddress(
-                            tunnelInterfaceInfo.mInterfaceName,
-                            localAddr.getAddress().getHostAddress(),
-                            localAddr.getPrefixLength());
+            mNetd.interfaceAddAddress(
+                    tunnelInterfaceInfo.mInterfaceName,
+                    localAddr.getAddress().getHostAddress(),
+                    localAddr.getPrefixLength());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1464,9 +1436,7 @@
         try {
             // We can assume general validity of the IP address, since we get them as a
             // LinkAddress, which does some validation.
-            mDeps
-                    .getNetdInstance(mContext)
-                    .interfaceDelAddress(
+            mNetd.interfaceDelAddress(
                             tunnelInterfaceInfo.mInterfaceName,
                             localAddr.getAddress().getHostAddress(),
                             localAddr.getPrefixLength());
@@ -1679,30 +1649,28 @@
             cryptName = crypt.getName();
         }
 
-        mDeps
-                .getNetdInstance(mContext)
-                .ipSecAddSecurityAssociation(
-                        Binder.getCallingUid(),
-                        c.getMode(),
-                        c.getSourceAddress(),
-                        c.getDestinationAddress(),
-                        (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0,
-                        spiRecord.getSpi(),
-                        c.getMarkValue(),
-                        c.getMarkMask(),
-                        (auth != null) ? auth.getName() : "",
-                        (auth != null) ? auth.getKey() : new byte[] {},
-                        (auth != null) ? auth.getTruncationLengthBits() : 0,
-                        cryptName,
-                        (crypt != null) ? crypt.getKey() : new byte[] {},
-                        (crypt != null) ? crypt.getTruncationLengthBits() : 0,
-                        (authCrypt != null) ? authCrypt.getName() : "",
-                        (authCrypt != null) ? authCrypt.getKey() : new byte[] {},
-                        (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0,
-                        encapType,
-                        encapLocalPort,
-                        encapRemotePort,
-                        c.getXfrmInterfaceId());
+        mNetd.ipSecAddSecurityAssociation(
+                Binder.getCallingUid(),
+                c.getMode(),
+                c.getSourceAddress(),
+                c.getDestinationAddress(),
+                (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0,
+                spiRecord.getSpi(),
+                c.getMarkValue(),
+                c.getMarkMask(),
+                (auth != null) ? auth.getName() : "",
+                (auth != null) ? auth.getKey() : new byte[] {},
+                (auth != null) ? auth.getTruncationLengthBits() : 0,
+                cryptName,
+                (crypt != null) ? crypt.getKey() : new byte[] {},
+                (crypt != null) ? crypt.getTruncationLengthBits() : 0,
+                (authCrypt != null) ? authCrypt.getName() : "",
+                (authCrypt != null) ? authCrypt.getKey() : new byte[] {},
+                (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0,
+                encapType,
+                encapLocalPort,
+                encapRemotePort,
+                c.getXfrmInterfaceId());
     }
 
     /**
@@ -1791,15 +1759,13 @@
                 c.getMode() == IpSecTransform.MODE_TRANSPORT,
                 "Transform mode was not Transport mode; cannot be applied to a socket");
 
-        mDeps
-                .getNetdInstance(mContext)
-                .ipSecApplyTransportModeTransform(
-                        socket,
-                        callingUid,
-                        direction,
-                        c.getSourceAddress(),
-                        c.getDestinationAddress(),
-                        info.getSpiRecord().getSpi());
+        mNetd.ipSecApplyTransportModeTransform(
+                socket,
+                callingUid,
+                direction,
+                c.getSourceAddress(),
+                c.getDestinationAddress(),
+                info.getSpiRecord().getSpi());
     }
 
     /**
@@ -1811,9 +1777,7 @@
     @Override
     public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket)
             throws RemoteException {
-        mDeps
-                .getNetdInstance(mContext)
-                .ipSecRemoveTransportModeTransform(socket);
+        mNetd.ipSecRemoveTransportModeTransform(socket);
     }
 
     /**
@@ -1888,18 +1852,16 @@
 
             // Always update the policy with the relevant XFRM_IF_ID
             for (int selAddrFamily : ADDRESS_FAMILIES) {
-                mDeps
-                        .getNetdInstance(mContext)
-                        .ipSecUpdateSecurityPolicy(
-                                callingUid,
-                                selAddrFamily,
-                                direction,
-                                transformInfo.getConfig().getSourceAddress(),
-                                transformInfo.getConfig().getDestinationAddress(),
-                                spi, // If outbound, also add SPI to the policy.
-                                mark, // Must always set policy mark; ikey/okey for VTIs
-                                0xffffffff,
-                                c.getXfrmInterfaceId());
+                mNetd.ipSecUpdateSecurityPolicy(
+                        callingUid,
+                        selAddrFamily,
+                        direction,
+                        transformInfo.getConfig().getSourceAddress(),
+                        transformInfo.getConfig().getDestinationAddress(),
+                        spi, // If outbound, also add SPI to the policy.
+                        mark, // Must always set policy mark; ikey/okey for VTIs
+                        0xffffffff,
+                        c.getXfrmInterfaceId());
             }
 
             // Update SA with tunnel mark (ikey or okey based on direction)
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 275e0a5..baf5336 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -390,36 +390,34 @@
                 android:focusable="false">
 
                 <FrameLayout
-                    android:id="@+id/apm_layout"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:clickable="true"
-                    android:focusable="true"
                     android:layout_gravity="start|center_vertical"
                     android:orientation="vertical">
                     <Button
+                        android:id="@+id/apm_button"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/turn_off_airplane_mode"
                         android:ellipsize="end"
                         style="@style/Widget.Dialog.Button.BorderButton"
-                        android:clickable="false"/>
+                        android:clickable="true"
+                        android:focusable="true"/>
                 </FrameLayout>
 
                 <FrameLayout
-                    android:id="@+id/done_layout"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_marginStart="16dp"
-                    android:layout_gravity="end|center_vertical"
-                    android:clickable="true"
-                    android:focusable="true">
+                    android:layout_gravity="end|center_vertical">
                     <Button
+                        android:id="@+id/done_button"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/inline_done_button"
                         style="@style/Widget.Dialog.Button"
-                        android:clickable="false"/>
+                        android:clickable="true"
+                        android:focusable="true"/>
                 </FrameLayout>
             </FrameLayout>
         </LinearLayout>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 38eded8..48fcbbd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -61,7 +61,7 @@
 public class ActivityManagerWrapper {
 
     private static final String TAG = "ActivityManagerWrapper";
-
+    private static final int NUM_RECENT_ACTIVITIES_REQUEST = 3;
     private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper();
 
     // Should match the values in PhoneWindowManager
@@ -113,6 +113,22 @@
     }
 
     /**
+     * We ask for {@link #NUM_RECENT_ACTIVITIES_REQUEST} activities because when in split screen,
+     * we'll get back 2 activities for each split app and one for launcher. Launcher might be more
+     * "recently" used than one of the split apps so if we only request 2 tasks, then we might miss
+     * out on one of the split apps
+     *
+     * @return an array of up to {@link #NUM_RECENT_ACTIVITIES_REQUEST} running tasks
+     *         filtering only for tasks that can be visible in the recent tasks list.
+     */
+    public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
+        // Note: The set of running tasks from the system is ordered by recency
+        List<ActivityManager.RunningTaskInfo> tasks =
+                mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST, filterOnlyVisibleRecents);
+        return tasks.toArray(new RunningTaskInfo[tasks.size()]);
+    }
+
+    /**
      * @return a list of the recents tasks.
      */
     public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index f13730e..3f5c2c8 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -171,8 +171,8 @@
         return mStatusBarStateController.isDozing();
     }
 
-    private boolean isLauncherShowing(ActivityManager.RunningTaskInfo runningTaskInfo) {
-        if (runningTaskInfo == null) {
+    private boolean isLauncherShowing(@Nullable ActivityManager.RunningTaskInfo runningTaskInfo) {
+        if (runningTaskInfo == null || runningTaskInfo.topActivity == null) {
             return false;
         } else {
             return runningTaskInfo.topActivity.equals(mDefaultHome);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 90d5624..0512d48 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2107,15 +2107,6 @@
     private final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
         @Override
         public void run() {
-            // If the keyguard is already going away, or it's about to because we are going to
-            // trigger the going-away remote animation to show the surface behind, don't do it
-            // again. That will cause the current animation to be cancelled unnecessarily.
-            if (mKeyguardStateController.isKeyguardGoingAway()
-                    || mSurfaceBehindRemoteAnimationRequested
-                    || mSurfaceBehindRemoteAnimationRunning) {
-                return;
-            }
-
             Trace.beginSection("KeyguardViewMediator.mKeyGuardGoingAwayRunnable");
             if (DEBUG) Log.d(TAG, "keyguardGoingAway");
             mKeyguardViewControllerLazy.get().keyguardGoingAway();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index a1f8455..1174fa8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -20,6 +20,8 @@
 import android.view.WindowManager;
 
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.media.MediaDataManager;
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
@@ -28,8 +30,10 @@
 import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
 import com.android.systemui.media.taptotransfer.MediaTttFlags;
 import com.android.systemui.statusbar.commandline.CommandRegistry;
+import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import java.util.Optional;
+import java.util.concurrent.Executor;
 
 import javax.inject.Named;
 
@@ -79,11 +83,14 @@
     static Optional<MediaTttChipController> providesMediaTttChipController(
             MediaTttFlags mediaTttFlags,
             Context context,
-            WindowManager windowManager) {
+            WindowManager windowManager,
+            @Main Executor mainExecutor,
+            @Background Executor backgroundExecutor) {
         if (!mediaTttFlags.isMediaTttEnabled()) {
             return Optional.empty();
         }
-        return Optional.of(new MediaTttChipController(context, windowManager));
+        return Optional.of(new MediaTttChipController(
+                context, windowManager, mainExecutor, backgroundExecutor));
     }
 
     /** */
@@ -92,10 +99,12 @@
     static Optional<MediaTttCommandLineHelper> providesMediaTttCommandLineHelper(
             MediaTttFlags mediaTttFlags,
             CommandRegistry commandRegistry,
-            MediaTttChipController mediaTttChipController) {
+            MediaTttChipController mediaTttChipController,
+            @Main DelayableExecutor mainExecutor) {
         if (!mediaTttFlags.isMediaTttEnabled()) {
             return Optional.empty();
         }
-        return Optional.of(new MediaTttCommandLineHelper(commandRegistry, mediaTttChipController));
+        return Optional.of(new MediaTttCommandLineHelper(
+                commandRegistry, mediaTttChipController, mainExecutor));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt
index 376fea2..baa469d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipController.kt
@@ -27,6 +27,10 @@
 import android.widget.TextView
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import java.util.concurrent.Executor
+import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
 const val TAG = "MediaTapToTransfer"
@@ -41,6 +45,8 @@
 class MediaTttChipController @Inject constructor(
     private val context: Context,
     private val windowManager: WindowManager,
+    @Main private val mainExecutor: Executor,
+    @Background private val backgroundExecutor: Executor,
 ) {
 
     @SuppressLint("WrongConstant") // We're allowed to use TYPE_VOLUME_OVERLAY
@@ -92,6 +98,11 @@
         }
         undoView.setOnClickListener(undoClickListener)
 
+        // Future handling
+        if (chipState is TransferInitiated) {
+            addFutureCallback(chipState)
+        }
+
         // Add view if necessary
         if (oldChipView == null) {
             windowManager.addView(chipView, windowLayoutParams)
@@ -104,4 +115,29 @@
         windowManager.removeView(chipView)
         chipView = null
     }
+
+    /**
+     * Adds the appropriate callbacks to [chipState.future] so that we update the chip correctly
+     * when the future resolves.
+     */
+    private fun addFutureCallback(chipState: TransferInitiated) {
+        // Listen to the future on a background thread so we don't occupy the main thread while we
+        // wait for it to complete.
+        backgroundExecutor.execute {
+            try {
+                val undoRunnable = chipState.future.get(TRANSFER_TIMEOUT_SECONDS, TimeUnit.SECONDS)
+                // Make UI changes on the main thread
+                mainExecutor.execute {
+                    displayChip(TransferSucceeded(chipState.otherDeviceName, undoRunnable))
+                }
+            } catch (ex: Exception) {
+                // TODO(b/203800327): Maybe show a failure chip here if UX decides we need one.
+                mainExecutor.execute {
+                    removeChip()
+                }
+            }
+        }
+    }
 }
+
+private const val TRANSFER_TIMEOUT_SECONDS = 10L
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt
index 3b3adfd..1f308a9a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttChipState.kt
@@ -18,6 +18,7 @@
 
 import androidx.annotation.StringRes
 import com.android.systemui.R
+import java.util.concurrent.Future
 
 /**
  * A class that stores all the information necessary to display the media tap-to-transfer chip in
@@ -43,9 +44,15 @@
 
 /**
  * A state representing that a transfer has been initiated (but not completed).
+ *
+ * @property future a future that will be resolved when the transfer has either succeeded or failed.
+ *   If the transfer succeeded, the future can optionally return an undo runnable (see
+ *   [TransferSucceeded.undoRunnable]). [MediaTttChipController] is responsible for transitioning
+ *   the chip to the [TransferSucceeded] state if the future resolves successfully.
  */
 class TransferInitiated(
-    otherDeviceName: String
+    otherDeviceName: String,
+    val future: Future<Runnable?>
 ) : MediaTttChipState(R.string.media_transfer_playing, otherDeviceName)
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
index 6a02dab..663037c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -19,9 +19,12 @@
 import android.util.Log
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.statusbar.commandline.Command
 import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.util.concurrency.DelayableExecutor
 import java.io.PrintWriter
+import java.util.concurrent.FutureTask
 import javax.inject.Inject
 
 /**
@@ -31,7 +34,8 @@
 @SysUISingleton
 class MediaTttCommandLineHelper @Inject constructor(
     commandRegistry: CommandRegistry,
-    private val mediaTttChipController: MediaTttChipController
+    private val mediaTttChipController: MediaTttChipController,
+    @Main private val mainExecutor: DelayableExecutor,
 ) {
     init {
         commandRegistry.registerCommand(ADD_CHIP_COMMAND_TAG) { AddChipCommand() }
@@ -46,7 +50,12 @@
                     mediaTttChipController.displayChip(MoveCloserToTransfer(otherDeviceName))
                 }
                 TRANSFER_INITIATED_COMMAND_NAME -> {
-                    mediaTttChipController.displayChip(TransferInitiated(otherDeviceName))
+                    val futureTask = FutureTask { fakeUndoRunnable }
+                    mediaTttChipController.displayChip(
+                        TransferInitiated(otherDeviceName, futureTask)
+                    )
+                    mainExecutor.executeDelayed({ futureTask.run() }, FUTURE_WAIT_TIME)
+
                 }
                 TRANSFER_SUCCEEDED_COMMAND_NAME -> {
                     mediaTttChipController.displayChip(
@@ -94,3 +103,5 @@
 val TRANSFER_INITIATED_COMMAND_NAME = TransferInitiated::class.simpleName!!
 @VisibleForTesting
 val TRANSFER_SUCCEEDED_COMMAND_NAME = TransferSucceeded::class.simpleName!!
+
+private const val FUTURE_WAIT_TIME = 2000L
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 11ecac2..e7982bf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -41,6 +41,7 @@
 import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
+import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -126,8 +127,8 @@
     private Switch mMobileDataToggle;
     private View mMobileToggleDivider;
     private Switch mWiFiToggle;
-    private FrameLayout mDoneLayout;
-    private FrameLayout mAirplaneModeLayout;
+    private Button mDoneButton;
+    private Button mAirplaneModeButton;
     private Drawable mBackgroundOn;
     private Drawable mBackgroundOff = null;
     private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -217,8 +218,8 @@
         mWifiSettingsIcon = mDialogView.requireViewById(R.id.wifi_settings_icon);
         mWifiRecyclerView = mDialogView.requireViewById(R.id.wifi_list_layout);
         mSeeAllLayout = mDialogView.requireViewById(R.id.see_all_layout);
-        mDoneLayout = mDialogView.requireViewById(R.id.done_layout);
-        mAirplaneModeLayout = mDialogView.requireViewById(R.id.apm_layout);
+        mDoneButton = mDialogView.requireViewById(R.id.done_button);
+        mAirplaneModeButton = mDialogView.requireViewById(R.id.apm_button);
         mSignalIcon = mDialogView.requireViewById(R.id.signal_icon);
         mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title);
         mMobileSummaryText = mDialogView.requireViewById(R.id.mobile_summary);
@@ -240,7 +241,7 @@
 
         setOnClickListener();
         mTurnWifiOnLayout.setBackground(null);
-        mAirplaneModeLayout.setVisibility(
+        mAirplaneModeButton.setVisibility(
                 mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
         mWifiRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
         mWifiRecyclerView.setAdapter(mAdapter);
@@ -280,8 +281,8 @@
         mConnectedWifListLayout.setOnClickListener(null);
         mSeeAllLayout.setOnClickListener(null);
         mWiFiToggle.setOnCheckedChangeListener(null);
-        mDoneLayout.setOnClickListener(null);
-        mAirplaneModeLayout.setOnClickListener(null);
+        mDoneButton.setOnClickListener(null);
+        mAirplaneModeButton.setOnClickListener(null);
         mInternetDialogController.onStop();
         mInternetDialogFactory.destroyDialog();
     }
@@ -307,7 +308,7 @@
         }
         mInternetDialogTitle.setText(getDialogTitleText());
         mInternetDialogSubTitle.setText(getSubtitleText());
-        mAirplaneModeLayout.setVisibility(
+        mAirplaneModeButton.setVisibility(
                 mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
 
         updateEthernet();
@@ -356,8 +357,8 @@
                     buttonView.setChecked(isChecked);
                     mWifiManager.setWifiEnabled(isChecked);
                 });
-        mDoneLayout.setOnClickListener(v -> dismiss());
-        mAirplaneModeLayout.setOnClickListener(v -> {
+        mDoneButton.setOnClickListener(v -> dismiss());
+        mAirplaneModeButton.setOnClickListener(v -> {
             mInternetDialogController.setAirplaneModeDisabled();
         });
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt
index bc0cff1..8749917 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttChipControllerTest.kt
@@ -23,8 +23,11 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.SettableFuture
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentCaptor
@@ -37,6 +40,11 @@
 @SmallTest
 class MediaTttChipControllerTest : SysuiTestCase() {
 
+    private lateinit var fakeMainClock: FakeSystemClock
+    private lateinit var fakeMainExecutor: FakeExecutor
+    private lateinit var fakeBackgroundClock: FakeSystemClock
+    private lateinit var fakeBackgroundExecutor: FakeExecutor
+
     private lateinit var mediaTttChipController: MediaTttChipController
 
     @Mock
@@ -45,7 +53,13 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        mediaTttChipController = MediaTttChipController(context, windowManager)
+        fakeMainClock = FakeSystemClock()
+        fakeMainExecutor = FakeExecutor(fakeMainClock)
+        fakeBackgroundClock = FakeSystemClock()
+        fakeBackgroundExecutor = FakeExecutor(fakeBackgroundClock)
+        mediaTttChipController = MediaTttChipController(
+            context, windowManager, fakeMainExecutor, fakeBackgroundExecutor
+        )
     }
 
     @Test
@@ -93,9 +107,13 @@
     }
 
     @Test
-    fun transferInitiated_chipTextContainsDeviceName_loadingIcon_noUndo() {
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME))
+    fun transferInitiated_futureNotResolvedYet_loadingIcon_noUndo() {
+        val future: SettableFuture<Runnable?> = SettableFuture.create()
+        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
 
+        // Don't resolve the future in any way and don't run our executors
+
+        // Assert we're still in the loading state
         val chipView = getChipView()
         assertThat(chipView.getChipText()).contains(DEVICE_NAME)
         assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
@@ -103,6 +121,65 @@
     }
 
     @Test
+    fun transferInitiated_futureResolvedSuccessfully_switchesToTransferSucceeded() {
+        val future: SettableFuture<Runnable?> = SettableFuture.create()
+        val undoRunnable = Runnable { }
+
+        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+
+        future.set(undoRunnable)
+        fakeBackgroundExecutor.advanceClockToLast()
+        fakeBackgroundExecutor.runAllReady()
+        fakeMainExecutor.advanceClockToLast()
+        val numRun = fakeMainExecutor.runAllReady()
+
+        // Assert we ran the future callback
+        assertThat(numRun).isEqualTo(1)
+        // Assert that we've moved to the successful state
+        val chipView = getChipView()
+        assertThat(chipView.getChipText()).contains(DEVICE_NAME)
+        assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE)
+        assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
+    }
+
+    @Test
+    fun transferInitiated_futureCancelled_chipRemoved() {
+        val future: SettableFuture<Runnable?> = SettableFuture.create()
+
+        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+
+        future.cancel(true)
+        fakeBackgroundExecutor.advanceClockToLast()
+        fakeBackgroundExecutor.runAllReady()
+        fakeMainExecutor.advanceClockToLast()
+        val numRun = fakeMainExecutor.runAllReady()
+
+        // Assert we ran the future callback
+        assertThat(numRun).isEqualTo(1)
+        // Assert that we've hidden the chip
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun transferInitiated_futureNotResolvedAfterTimeout_chipRemoved() {
+        val future: SettableFuture<Runnable?> = SettableFuture.create()
+        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, future))
+
+        // We won't set anything on the future, but we will still run the executors so that we're
+        // waiting on the future resolving. If we have a bug in our code, then this test will time
+        // out because we're waiting on the future indefinitely.
+        fakeBackgroundExecutor.advanceClockToLast()
+        fakeBackgroundExecutor.runAllReady()
+        fakeMainExecutor.advanceClockToLast()
+        val numRun = fakeMainExecutor.runAllReady()
+
+        // Assert we eventually decide to not wait for the future anymore
+        assertThat(numRun).isEqualTo(1)
+        // Assert we've hidden the chip
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
     fun transferSucceededNullUndoRunnable_chipTextContainsDeviceName_noLoadingIcon_noUndo() {
         mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME, undoRunnable = null))
 
@@ -137,14 +214,14 @@
     @Test
     fun changeFromCloserToTransferToTransferInitiated_loadingIconAppears() {
         mediaTttChipController.displayChip(MoveCloserToTransfer(DEVICE_NAME))
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME))
+        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, TEST_FUTURE))
 
         assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
     }
 
     @Test
     fun changeFromTransferInitiatedToTransferSucceeded_loadingIconDisappears() {
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME))
+        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, TEST_FUTURE))
         mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME))
 
         assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE)
@@ -152,7 +229,7 @@
 
     @Test
     fun changeFromTransferInitiatedToTransferSucceeded_undoButtonAppears() {
-        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME))
+        mediaTttChipController.displayChip(TransferInitiated(DEVICE_NAME, TEST_FUTURE))
         mediaTttChipController.displayChip(TransferSucceeded(DEVICE_NAME) { })
 
         assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -182,3 +259,6 @@
 }
 
 private const val DEVICE_NAME = "My Tablet"
+// Use a settable future that hasn't yet been set so that we don't immediately switch to the success
+// state.
+private val TEST_FUTURE: SettableFuture<Runnable?> = SettableFuture.create()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
index 4b85fa9..9b2d3eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
@@ -20,7 +20,9 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.commandline.Command
 import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.time.FakeSystemClock
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mock
@@ -46,7 +48,9 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         mediaTttCommandLineHelper =
-            MediaTttCommandLineHelper(commandRegistry, mediaTttChipController)
+            MediaTttCommandLineHelper(
+                commandRegistry, mediaTttChipController, FakeExecutor(FakeSystemClock())
+            )
     }
 
     @Test(expected = IllegalStateException::class)
diff --git a/services/Android.bp b/services/Android.bp
index dcbcff0..c830c22 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -90,6 +90,7 @@
         ":services.profcollect-sources",
         ":services.restrictions-sources",
         ":services.searchui-sources",
+        ":services.selectiontoolbar-sources",
         ":services.smartspace-sources",
         ":services.speech-sources",
         ":services.startop.iorap-sources",
@@ -144,6 +145,7 @@
         "services.profcollect",
         "services.restrictions",
         "services.searchui",
+        "services.selectiontoolbar",
         "services.smartspace",
         "services.speech",
         "services.startop",
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 91cd2f6..d7c1cfb 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -366,7 +366,7 @@
 
     private List<BarringInfo> mBarringInfo = null;
 
-    private boolean mCarrierNetworkChangeState = false;
+    private boolean[] mCarrierNetworkChangeState = null;
 
     private PhoneCapability mPhoneCapability = null;
 
@@ -675,6 +675,7 @@
         mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones);
         mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones);
         mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
+        mCarrierNetworkChangeState = copyOf(mCarrierNetworkChangeState, mNumPhones);
         mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones);
         mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones);
         mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones);
@@ -720,6 +721,7 @@
             mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
+            mCarrierNetworkChangeState[i] = false;
             mTelephonyDisplayInfos[i] = null;
             mIsDataEnabled[i] = false;
             mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
@@ -784,6 +786,7 @@
         mOutgoingCallEmergencyNumber = new EmergencyNumber[numPhones];
         mOutgoingSmsEmergencyNumber = new EmergencyNumber[numPhones];
         mBarringInfo = new ArrayList<>();
+        mCarrierNetworkChangeState = new boolean[numPhones];
         mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones];
         mPhysicalChannelConfigs = new ArrayList<>();
         mAllowedNetworkTypeReason = new int[numPhones];
@@ -820,6 +823,7 @@
             mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
             mPreciseDataConnectionStates.add(new ArrayMap<>());
             mBarringInfo.add(i, new BarringInfo());
+            mCarrierNetworkChangeState[i] = false;
             mTelephonyDisplayInfos[i] = null;
             mIsDataEnabled[i] = false;
             mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER;
@@ -1230,7 +1234,7 @@
                 }
                 if (events.contains(TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED)) {
                     try {
-                        r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
+                        r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState[r.phoneId]);
                     } catch (RemoteException ex) {
                         remove(r.binder);
                     }
@@ -1724,23 +1728,37 @@
             throw new SecurityException("notifyCarrierNetworkChange without carrier privilege");
         }
 
-        synchronized (mRecords) {
-            mCarrierNetworkChangeState = active;
-            for (int subId : subIds) {
-                int phoneId = getPhoneIdFromSubId(subId);
+        for (int subId : subIds) {
+            notifyCarrierNetworkChangeWithPermission(subId, active);
+        }
+    }
 
-                if (VDBG) {
-                    log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId);
-                }
-                for (Record r : mRecords) {
-                    if (r.matchTelephonyCallbackEvent(
-                            TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED)
-                            && idMatch(r, subId, phoneId)) {
-                        try {
-                            r.callback.onCarrierNetworkChange(active);
-                        } catch (RemoteException ex) {
-                            mRemoveList.add(r.binder);
-                        }
+    @Override
+    public void notifyCarrierNetworkChangeWithSubId(int subId, boolean active) {
+        if (!TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext, subId)) {
+            throw new SecurityException(
+                    "notifyCarrierNetworkChange without carrier privilege on subId " + subId);
+        }
+
+        notifyCarrierNetworkChangeWithPermission(subId, active);
+    }
+
+    private void notifyCarrierNetworkChangeWithPermission(int subId, boolean active) {
+        synchronized (mRecords) {
+            int phoneId = getPhoneIdFromSubId(subId);
+            mCarrierNetworkChangeState[phoneId] = active;
+
+            if (VDBG) {
+                log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId);
+            }
+            for (Record r : mRecords) {
+                if (r.matchTelephonyCallbackEvent(
+                        TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED)
+                        && idMatch(r, subId, phoneId)) {
+                    try {
+                        r.callback.onCarrierNetworkChange(active);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
                     }
                 }
             }
@@ -2788,6 +2806,7 @@
                 pw.println("mOutgoingCallEmergencyNumber=" + mOutgoingCallEmergencyNumber[i]);
                 pw.println("mOutgoingSmsEmergencyNumber=" + mOutgoingSmsEmergencyNumber[i]);
                 pw.println("mBarringInfo=" + mBarringInfo.get(i));
+                pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState[i]);
                 pw.println("mTelephonyDisplayInfo=" + mTelephonyDisplayInfos[i]);
                 pw.println("mIsDataEnabled=" + mIsDataEnabled);
                 pw.println("mDataEnabledReason=" + mDataEnabledReason);
@@ -2797,7 +2816,7 @@
                 pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i));
                 pw.decreaseIndent();
             }
-            pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
+
             pw.println("mPhoneCapability=" + mPhoneCapability);
             pw.println("mActiveDataSubId=" + mActiveDataSubId);
             pw.println("mRadioPowerState=" + mRadioPowerState);
diff --git a/services/core/java/com/android/server/communal/CommunalManagerService.java b/services/core/java/com/android/server/communal/CommunalManagerService.java
index 3bf6ca2..df95bf5 100644
--- a/services/core/java/com/android/server/communal/CommunalManagerService.java
+++ b/services/core/java/com/android/server/communal/CommunalManagerService.java
@@ -87,7 +87,7 @@
             new ActivityInterceptorCallback() {
                 @Nullable
                 @Override
-                public Intent intercept(ActivityInterceptorInfo info) {
+                public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
                     if (!shouldIntercept(info.aInfo)) {
                         if (DEBUG) {
                             Slog.d(TAG, "Activity allowed, not intercepting: "
@@ -110,8 +110,10 @@
                             PendingIntent.FLAG_IMMUTABLE,
                             /* bOptions= */ null);
 
-                    return LaunchAfterAuthenticationActivity.createLaunchAfterAuthenticationIntent(
-                            new IntentSender(target));
+                    return new ActivityInterceptResult(
+                            LaunchAfterAuthenticationActivity.createLaunchAfterAuthenticationIntent(
+                                    new IntentSender(target)),
+                            info.checkedOptions);
 
                 }
             };
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index bf4ef48..e145d03 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1208,8 +1208,11 @@
             for (RouteInfo route : mConfig.routes) {
                 lp.addRoute(route);
                 InetAddress address = route.getDestination().getAddress();
-                allowIPv4 |= address instanceof Inet4Address;
-                allowIPv6 |= address instanceof Inet6Address;
+
+                if (route.getType() == RouteInfo.RTN_UNICAST) {
+                    allowIPv4 |= address instanceof Inet4Address;
+                    allowIPv6 |= address instanceof Inet6Address;
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 4c56999..c0a6abf 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -45,7 +45,10 @@
 import android.companion.virtual.IVirtualDevice;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
@@ -421,6 +424,32 @@
     // Receives notifications about changes to Settings.
     private SettingsObserver mSettingsObserver;
 
+    // Keeps note of what state the device is in, used for idle screen brightness mode.
+    private boolean mIsDocked;
+    private boolean mIsDreaming;
+
+    private final BroadcastReceiver mIdleModeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final DisplayManagerInternal dmi =
+                    LocalServices.getService(DisplayManagerInternal.class);
+            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
+                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
+                mIsDocked = dockState == Intent.EXTRA_DOCK_STATE_DESK
+                        || dockState == Intent.EXTRA_DOCK_STATE_LE_DESK
+                        || dockState == Intent.EXTRA_DOCK_STATE_HE_DESK;
+            }
+            if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
+                mIsDreaming = true;
+            } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
+                mIsDreaming = false;
+            }
+            setDockedAndIdleEnabled(/* enabled= */(mIsDocked && mIsDreaming),
+                    Display.DEFAULT_DISPLAY);
+        }
+    };
+
     private final boolean mAllowNonNativeRefreshRateOverride;
 
     private final BrightnessSynchronizer mBrightnessSynchronizer;
@@ -616,6 +645,13 @@
         mSettingsObserver = new SettingsObserver();
 
         mBrightnessSynchronizer.startSynchronizing();
+
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_DREAMING_STARTED);
+        filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+        filter.addAction(Intent.ACTION_DOCK_EVENT);
+
+        mContext.registerReceiver(mIdleModeReceiver, filter);
     }
 
     @VisibleForTesting
@@ -2096,6 +2132,16 @@
         }
     }
 
+    void setDockedAndIdleEnabled(boolean enabled, int displayId) {
+        synchronized (mSyncRoot) {
+            final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(
+                    displayId);
+            if (displayPowerController != null) {
+                displayPowerController.setAutomaticScreenBrightnessMode(enabled);
+            }
+        }
+    }
+
     private void clearViewportsLocked() {
         mViewports.clear();
     }
diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
index 43a850c..9a7ddcb 100644
--- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
+++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
@@ -76,6 +76,10 @@
                 return setUserDisabledHdrTypes();
             case "get-user-disabled-hdr-types":
                 return getUserDisabledHdrTypes();
+            case "dock":
+                return setDockedAndIdle();
+            case "undock":
+                return unsetDockedAndIdle();
             default:
                 return handleDefaultCommands(cmd);
         }
@@ -124,6 +128,10 @@
         pw.println("    Sets the user disabled HDR types as TYPES");
         pw.println("  get-user-disabled-hdr-types");
         pw.println("    Returns the user disabled HDR types");
+        pw.println("  dock");
+        pw.println("    Sets brightness to docked + idle screen brightness mode");
+        pw.println("  undock");
+        pw.println("    Sets brightness to active (normal) screen brightness mode");
         pw.println();
         Intent.printIntentArgsHelp(pw , "");
     }
@@ -345,4 +353,14 @@
                 return -1;
         }
     }
+
+    private int setDockedAndIdle() {
+        mService.setDockedAndIdleEnabled(true, Display.DEFAULT_DISPLAY);
+        return 0;
+    }
+
+    private int unsetDockedAndIdle() {
+        mService.setDockedAndIdleEnabled(false, Display.DEFAULT_DISPLAY);
+        return 0;
+    }
 }
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index c82b16d..efd2f6f 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -41,7 +41,6 @@
 import android.os.IThermalService;
 import android.os.Looper;
 import android.os.Message;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -619,10 +618,11 @@
             mAppRequestObserver.dumpLocked(pw);
             mBrightnessObserver.dumpLocked(pw);
             mUdfpsObserver.dumpLocked(pw);
-            mSensorObserver.dumpLocked(pw);
             mHbmObserver.dumpLocked(pw);
             mSkinThermalStatusObserver.dumpLocked(pw);
         }
+
+        mSensorObserver.dump(pw);
     }
 
     private void updateVoteLocked(int priority, Vote vote) {
@@ -2244,7 +2244,7 @@
             }
         }
 
-        void dumpLocked(PrintWriter pw) {
+        void dump(PrintWriter pw) {
             pw.println("  SensorObserver");
             synchronized (mSensorObserverLock) {
                 pw.println("    mIsProxActive=" + mIsProxActive);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index b46ee27..2dfaa8b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -395,11 +395,6 @@
     @Nullable
     private BrightnessMappingStrategy mIdleModeBrightnessMapper;
 
-    // If these are both true, and mIdleModeBrightnessMapper != null,
-    // then we are in idle screen brightness mode.
-    private boolean mIsDreaming;
-    private boolean mIsDocked;
-
     // The current brightness configuration.
     @Nullable
     private BrightnessConfiguration mBrightnessConfiguration;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 4082afd..bcd0708 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -34,7 +34,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -141,7 +141,7 @@
      * allow 3P apps to trigger internal-only functionality.
      */
     @ChangeId
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
     private static final long ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS = 161252188;
 
     /**
diff --git a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
index 873d688..d70f970 100644
--- a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
@@ -1549,6 +1549,25 @@
         }
 
         @Override
+        public void onCommandRequest(@TvIAppService.IAppServiceCommandType String cmdType,
+                Bundle parameters) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slogf.d(TAG, "onCommandRequest (cmdType=" + cmdType + ", parameters="
+                            + parameters.toString() + ")");
+                }
+                if (mSessionState.mSession == null || mSessionState.mClient == null) {
+                    return;
+                }
+                try {
+                    mSessionState.mClient.onCommandRequest(cmdType, parameters, mSessionState.mSeq);
+                } catch (RemoteException e) {
+                    Slogf.e(TAG, "error in onCommandRequest", e);
+                }
+            }
+        }
+
+        @Override
         public void onSessionStateChanged(int state) {
             synchronized (mLock) {
                 if (DEBUG) {
diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
index d736ede..30cd3c4 100644
--- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
+++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.app.TaskInfo;
@@ -33,12 +34,13 @@
 public abstract class ActivityInterceptorCallback {
     /**
      * Intercept the launch intent based on various signals. If an interception happened, returns
-     * a new/existing non-null {@link Intent} which may redirect to another activity.
+     * a new/existing non-null {@link ActivityInterceptResult} which may redirect to another
+     * activity or with new {@link ActivityOptions}.
      *
-     * @return null if no interception occurred, or a non-null intent which replaces the
-     * existing intent.
+     * @return null if no interception occurred, or a non-null result which replaces the existing
+     * intent and activity options.
      */
-    public abstract @Nullable Intent intercept(ActivityInterceptorInfo info);
+    public abstract @Nullable ActivityInterceptResult intercept(ActivityInterceptorInfo info);
 
     /**
      * Called when an activity is successfully launched.
@@ -108,4 +110,19 @@
             this.checkedOptions = checkedOptions;
         }
     }
+
+    /**
+     * Data class for storing the intercept result.
+     */
+    public static final class ActivityInterceptResult {
+        @NonNull public final Intent intent;
+        @NonNull public final ActivityOptions activityOptions;
+
+        public ActivityInterceptResult(
+                @NonNull Intent intent,
+                @NonNull ActivityOptions activityOptions) {
+            this.intent = intent;
+            this.activityOptions = activityOptions;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 352a070..658a17b 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -61,6 +61,7 @@
 import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.server.LocalServices;
 import com.android.server.am.ActivityManagerService;
+import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult;
 
 /**
  * A class that contains activity intercepting logic for {@link ActivityStarter#startActivityLocked}
@@ -194,11 +195,12 @@
 
         for (int i = 0; i < callbacks.size(); i++) {
             final ActivityInterceptorCallback callback = callbacks.valueAt(i);
-            final Intent newIntent = callback.intercept(interceptorInfo);
-            if (newIntent == null) {
+            final ActivityInterceptResult interceptResult = callback.intercept(interceptorInfo);
+            if (interceptResult == null) {
                 continue;
             }
-            mIntent = newIntent;
+            mIntent = interceptResult.intent;
+            mActivityOptions = interceptResult.activityOptions;
             mCallingPid = mRealCallingPid;
             mCallingUid = mRealCallingUid;
             mRInfo = mSupervisor.resolveIntent(mIntent, null, mUserId, 0, mRealCallingUid);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7416564..343b147 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1843,6 +1843,17 @@
         }
     }
 
+    /** Returns {@code true} if the decided new rotation has not applied to configuration yet. */
+    private boolean isRotationChanging() {
+        return mDisplayRotation.getRotation() != getWindowConfiguration().getRotation();
+    }
+
+    private void startFadeRotationAnimationIfNeeded() {
+        if (isRotationChanging()) {
+            startFadeRotationAnimation(false /* shouldDebounce */);
+        }
+    }
+
     /**
      * Starts the hide animation for the windows which will be rotated seamlessly.
      *
@@ -3189,11 +3200,8 @@
 
         // Hide the windows which are not significant in rotation animation. So that the windows
         // don't need to block the unfreeze time.
-        if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()
-                // Do not fade for freezing without rotation change.
-                && mDisplayRotation.getRotation() != getWindowConfiguration().getRotation()
-                && mFadeRotationAnimationController == null) {
-            startFadeRotationAnimation(false /* shouldDebounce */);
+        if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) {
+            startFadeRotationAnimationIfNeeded();
         }
     }
 
@@ -3214,6 +3222,7 @@
             }
             if (!controller.isCollecting(this)) {
                 controller.collect(this);
+                startFadeRotationAnimationIfNeeded();
             }
             return;
         }
@@ -3221,7 +3230,7 @@
                 this, this, null /* remoteTransition */, displayChange);
         if (t != null) {
             mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
-            if (getRotation() != getWindowConfiguration().getRotation()) {
+            if (isRotationChanging()) {
                 mWmService.mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
                 controller.mTransitionMetricsReporter.associate(t,
                         startTime -> mWmService.mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN));
diff --git a/services/core/java/com/android/server/wm/FadeAnimationController.java b/services/core/java/com/android/server/wm/FadeAnimationController.java
index 817b27a..561a070 100644
--- a/services/core/java/com/android/server/wm/FadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeAnimationController.java
@@ -21,7 +21,6 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
-import android.util.ArrayMap;
 import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
 import android.view.animation.Animation;
@@ -38,7 +37,6 @@
 public class FadeAnimationController {
     protected final DisplayContent mDisplayContent;
     protected final Context mContext;
-    protected final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>();
 
     public FadeAnimationController(DisplayContent displayContent) {
         mDisplayContent = displayContent;
@@ -78,16 +76,8 @@
             return;
         }
 
-        // We deferred the end of the animation when hiding the token, so we need to end it now that
-        // it's shown again.
-        final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
-            final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken);
-            if (runnable != null) {
-                runnable.run();
-            }
-        } : null;
         windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
-                show /* hidden */, animationType, finishedCallback);
+                show /* hidden */, animationType, null /* finishedCallback */);
     }
 
     protected FadeAnimationAdapter createAdapter(LocalAnimationAdapter.AnimationSpec animationSpec,
@@ -135,7 +125,7 @@
         };
     }
 
-    protected class FadeAnimationAdapter extends LocalAnimationAdapter {
+    protected static class FadeAnimationAdapter extends LocalAnimationAdapter {
         protected final boolean mShow;
         protected final WindowToken mToken;
 
@@ -149,13 +139,10 @@
 
         @Override
         public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
-            // We defer the end of the hide animation to ensure the tokens stay hidden until
-            // we show them again.
-            if (!mShow) {
-                mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback);
-                return true;
-            }
-            return false;
+            // Defer the finish callback (restore leash) of the hide animation to ensure the token
+            // stay hidden until it needs to show again. Besides, when starting the show animation,
+            // the previous hide animation will be cancelled, so the callback can be ignored.
+            return !mShow;
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
index cf36c85..bbda577 100644
--- a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
@@ -50,7 +50,7 @@
     /** Whether to use constant zero alpha animation. */
     private boolean mHideImmediately;
 
-    /** Whether this controller is triggered from shell transition. */
+    /** Whether this controller is triggered from shell transition with type CHANGE. */
     private final boolean mIsChangeTransition;
 
     /** Whether the start transaction of the transition is committed (by shell). */
@@ -59,21 +59,30 @@
     /** The list to store the drawn tokens before the rotation animation starts. */
     private ArrayList<WindowToken> mPendingShowTokens;
 
+    /** It is used when the display has rotated, but some windows fade out in old rotation. */
+    private SeamlessRotator mRotator;
+
+    private final int mOriginalRotation;
+    private final boolean mHasScreenRotationAnimation;
+
     public FadeRotationAnimationController(DisplayContent displayContent) {
         super(displayContent);
         mService = displayContent.mWmService;
-        mIsChangeTransition = displayContent.inTransition()
-                && displayContent.mTransitionController.getCollectingTransitionType()
-                == WindowManager.TRANSIT_CHANGE;
+        mOriginalRotation = displayContent.getWindowConfiguration().getRotation();
+        final int transitionType =
+                displayContent.mTransitionController.getCollectingTransitionType();
+        mIsChangeTransition = transitionType == WindowManager.TRANSIT_CHANGE;
+        // Only CHANGE type (rotation animation) needs to wait for the start transaction.
         mIsStartTransactionCommitted = !mIsChangeTransition;
-        mTimeoutRunnable = displayContent.getRotationAnimation() != null
-                || mIsChangeTransition ? () -> {
+        mTimeoutRunnable = displayContent.inTransition() ? () -> {
             synchronized (mService.mGlobalLock) {
                 displayContent.finishFadeRotationAnimationIfPossible();
                 mService.mWindowPlacerLocked.performSurfacePlacement();
             }
         } : null;
-        if (mTimeoutRunnable != null) {
+        mHasScreenRotationAnimation =
+                displayContent.getRotationAnimation() != null || mIsChangeTransition;
+        if (mHasScreenRotationAnimation) {
             // Hide the windows immediately because screen should have been covered by screenshot.
             mHideImmediately = true;
         }
@@ -103,6 +112,19 @@
         }, true /* traverseTopToBottom */);
     }
 
+    @Override
+    public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
+        if (show) {
+            final SurfaceControl leash = mTargetWindowTokens.remove(windowToken);
+            if (leash != null && mRotator != null) {
+                // The leash was unrotated by start transaction of transition. Clear the transform
+                // to reshow the window in current rotation.
+                mRotator.setIdentityMatrix(mDisplayContent.getPendingTransaction(), leash);
+            }
+        }
+        super.fadeWindowToken(show, windowToken, animationType);
+    }
+
     /** Applies show animation on the previously hidden window tokens. */
     void show() {
         for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
@@ -125,19 +147,23 @@
      * controller is created for normal rotation.
      */
     boolean show(WindowToken token) {
+        if (!isTargetToken(token)) return false;
         if (!mIsStartTransactionCommitted) {
             // The fade-in animation should only start after the screenshot layer is shown by shell.
             // Otherwise the window will be blinking before the rotation animation starts. So store
             // to a pending list and animate them until the transaction is committed.
-            if (mTargetWindowTokens.containsKey(token)) {
-                if (mPendingShowTokens == null) {
-                    mPendingShowTokens = new ArrayList<>();
-                }
-                mPendingShowTokens.add(token);
+            if (mPendingShowTokens == null) {
+                mPendingShowTokens = new ArrayList<>();
             }
+            mPendingShowTokens.add(token);
             return false;
         }
-        if (mTimeoutRunnable != null && mTargetWindowTokens.remove(token) != null) {
+        if (!mHasScreenRotationAnimation && token.mTransitionController.inTransition()) {
+            // Defer showing to onTransitionFinished().
+            return false;
+        }
+        // If the timeout runnable is null (fixed rotation), the case will be handled by show().
+        if (mTimeoutRunnable != null) {
             fadeWindowToken(true /* show */, token, ANIMATION_TYPE_FIXED_TRANSFORM);
             if (mTargetWindowTokens.isEmpty()) {
                 mService.mH.removeCallbacks(mTimeoutRunnable);
@@ -177,6 +203,15 @@
         return mTargetWindowTokens.containsKey(token);
     }
 
+    /**
+     * Whether the insets animation leash should use previous position when running fade out
+     * animation in rotated display.
+     */
+    boolean shouldFreezeInsetsPosition(WindowState w) {
+        return !mHasScreenRotationAnimation && w.mTransitionController.inTransition()
+                && isTargetToken(w.mToken);
+    }
+
     void setOnShowRunnable(Runnable onShowRunnable) {
         mOnShowRunnable = onShowRunnable;
     }
@@ -186,6 +221,22 @@
      * transition starts. And associate transaction callback to consume pending animations.
      */
     void setupStartTransaction(SurfaceControl.Transaction t) {
+        if (!mIsChangeTransition) {
+            // Take OPEN/CLOSE transition type as the example, the non-activity windows need to
+            // fade out in previous rotation while display has rotated to the new rotation, so
+            // their leashes are unrotated with the start transaction.
+            mRotator = new SeamlessRotator(mOriginalRotation,
+                    mDisplayContent.getWindowConfiguration().getRotation(),
+                    mDisplayContent.getDisplayInfo(),
+                    false /* applyFixedTransformationHint */);
+            for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
+                final SurfaceControl leash = mTargetWindowTokens.valueAt(i);
+                if (leash != null) {
+                    mRotator.applyTransform(t, leash);
+                }
+            }
+            return;
+        }
         // Hide the windows immediately because a screenshot layer should cover the screen.
         for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
             final SurfaceControl leash = mTargetWindowTokens.valueAt(i);
@@ -208,9 +259,30 @@
         });
     }
 
+    void onTransitionFinished() {
+        if (mIsChangeTransition) {
+            // With screen rotation animation, the windows are always faded in when they are drawn.
+            // Because if they are drawn fast enough, the fade animation should not be observable.
+            return;
+        }
+        // For other transition types, the fade-in animation runs after the transition to make the
+        // transition animation (e.g. launch activity) look cleaner.
+        for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
+            final WindowToken token = mTargetWindowTokens.keyAt(i);
+            for (int j = token.getChildCount() - 1; j >= 0; j--) {
+                // Only fade in the drawn windows. If the remaining windows are drawn later,
+                // show(WindowToken) will be called to fade in them.
+                if (token.getChildAt(j).isDrawFinishedLw()) {
+                    mDisplayContent.finishFadeRotationAnimation(token);
+                    break;
+                }
+            }
+        }
+    }
+
     @Override
     public Animation getFadeInAnimation() {
-        if (mTimeoutRunnable != null) {
+        if (mHasScreenRotationAnimation) {
             // Use a shorter animation so it is easier to align with screen rotation animation.
             return AnimationUtils.loadAnimation(mContext, R.anim.screen_rotate_0_enter);
         }
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index af91726..a8a9231 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -297,6 +297,14 @@
     }
 
     private Point getWindowFrameSurfacePosition() {
+        if (mControl != null) {
+            final FadeRotationAnimationController fadeController =
+                    mWin.mDisplayContent.getFadeRotationAnimationController();
+            if (fadeController != null && fadeController.shouldFreezeInsetsPosition(mWin)) {
+                // Use previous position because the fade-out animation runs in old rotation.
+                return mControl.getSurfacePosition();
+            }
+        }
         final Rect frame = mWin.getFrame();
         final Point position = new Point();
         mWin.transformFrameToSurfacePosition(frame.left, frame.top, position);
diff --git a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
index af8293a..80f2ab6 100644
--- a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
@@ -95,14 +95,6 @@
             } else {
                 fadeAnim.run();
             }
-        } else {
-            // If fade rotation animation is running and controlling the nav bar, make sure we empty
-            // the mDeferredFinishCallbacks and defer the runnable until fade rotation animation
-            // finishes.
-            final Runnable runnable = mDeferredFinishCallbacks.remove(mNavigationBar.mToken);
-            if (runnable != null) {
-                controller.setOnShowRunnable(runnable);
-            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index 9ad30da..1da0fe7 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -243,7 +243,8 @@
             int oldRotation, int newRotation) {
         final Rect bounds = mDestRotatedBounds;
         final PictureInPictureSurfaceTransaction pipTx = mPipTransaction;
-        if (bounds == null && pipTx == null) {
+        final boolean emptyPipPositionTx = pipTx == null || pipTx.mPosition == null;
+        if (bounds == null && emptyPipPositionTx) {
             return;
         }
         final TaskDisplayArea taskArea = mDisplayContent.getDefaultTaskDisplayArea();
@@ -255,7 +256,7 @@
         mDestRotatedBounds = null;
         mPipTransaction = null;
         final Rect areaBounds = taskArea.getBounds();
-        if (pipTx != null && pipTx.mPosition != null) {
+        if (!emptyPipPositionTx) {
             // The transaction from recents animation is in old rotation. So the position needs to
             // be rotated.
             float dx = pipTx.mPosition.x;
diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java
index 4cc369f..c20b858 100644
--- a/services/core/java/com/android/server/wm/SeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/SeamlessRotator.java
@@ -20,7 +20,6 @@
 import static android.view.Surface.ROTATION_90;
 
 import android.graphics.Matrix;
-import android.os.IBinder;
 import android.view.DisplayInfo;
 import android.view.Surface.Rotation;
 import android.view.SurfaceControl;
@@ -73,7 +72,7 @@
      * global display rotation.
      */
     public void unrotate(Transaction transaction, WindowContainer win) {
-        transaction.setMatrix(win.getSurfaceControl(), mTransform, mFloat9);
+        applyTransform(transaction, win.getSurfaceControl());
         // WindowState sets the position of the window so transform the position and update it.
         final float[] winSurfacePos = {win.mLastSurfacePosition.x, win.mLastSurfacePosition.y};
         mTransform.mapPoints(winSurfacePos);
@@ -83,6 +82,10 @@
         }
     }
 
+    void applyTransform(Transaction t, SurfaceControl sc) {
+        t.setMatrix(sc, mTransform, mFloat9);
+    }
+
     /**
      * Returns the rotation of the display before it started rotating.
      *
@@ -106,14 +109,17 @@
             return;
         }
 
-        mTransform.reset();
-        t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
+        setIdentityMatrix(t, win.mSurfaceControl);
         t.setPosition(win.mSurfaceControl, win.mLastSurfacePosition.x, win.mLastSurfacePosition.y);
         if (mApplyFixedTransformHint) {
             t.unsetFixedTransformHint(win.mSurfaceControl);
         }
     }
 
+    void setIdentityMatrix(Transaction t, SurfaceControl sc) {
+        t.setMatrix(sc, Matrix.IDENTITY_MATRIX, mFloat9);
+    }
+
     public void dump(PrintWriter pw) {
         pw.print("{old="); pw.print(mOldRotation); pw.print(", new="); pw.print(mNewRotation);
         pw.print("}");
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index dae004d..c7c3bb6 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -143,6 +143,9 @@
     /** The final animation targets derived from participants after promotion. */
     private ArraySet<WindowContainer> mTargets = null;
 
+    /** The main display running this transition. */
+    private DisplayContent mTargetDisplay;
+
     /**
      * Set of participating windowtokens (activity/wallpaper) which are visible at the end of
      * the transition animation.
@@ -473,6 +476,12 @@
                     mController.mAtm.mRootWindowContainer.getDisplayContent(mRecentsDisplayId);
             dc.getInputMonitor().setActiveRecents(null /* activity */, null /* layer */);
         }
+
+        final FadeRotationAnimationController fadeRotationController =
+                mTargetDisplay.getFadeRotationAnimationController();
+        if (fadeRotationController != null) {
+            fadeRotationController.onTransitionFinished();
+        }
     }
 
     void abort() {
@@ -514,6 +523,7 @@
             }
         }
         if (dc == null) dc = mController.mAtm.mRootWindowContainer.getDefaultDisplay();
+        mTargetDisplay = dc;
 
         if (mState == STATE_ABORT) {
             mController.abort(this);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index bfceeda..23b685f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -91,18 +91,18 @@
 import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
 import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR;
 import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
-import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED;
-import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_PRE_CONDITION_FAILED;
-import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_PROFILE_CREATION_FAILED;
-import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED;
-import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED;
-import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED;
-import static android.app.admin.DevicePolicyManager.PROVISIONING_RESULT_STARTING_PROFILE_FAILED;
 import static android.app.admin.DevicePolicyManager.STATE_USER_UNMANAGED;
 import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
 import static android.app.admin.DevicePolicyManager.WIPE_SILENTLY;
+import static android.app.admin.ProvisioningException.ERROR_ADMIN_PACKAGE_INSTALLATION_FAILED;
+import static android.app.admin.ProvisioningException.ERROR_PRE_CONDITION_FAILED;
+import static android.app.admin.ProvisioningException.ERROR_PROFILE_CREATION_FAILED;
+import static android.app.admin.ProvisioningException.ERROR_REMOVE_NON_REQUIRED_APPS_FAILED;
+import static android.app.admin.ProvisioningException.ERROR_SETTING_PROFILE_OWNER_FAILED;
+import static android.app.admin.ProvisioningException.ERROR_SET_DEVICE_OWNER_FAILED;
+import static android.app.admin.ProvisioningException.ERROR_STARTING_PROFILE_FAILED;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
@@ -10653,15 +10653,6 @@
         }
 
         final int userHandle = user.getIdentifier();
-        final Intent intent = new Intent(DevicePolicyManager.ACTION_MANAGED_USER_CREATED)
-                .putExtra(Intent.EXTRA_USER_HANDLE, userHandle)
-                .putExtra(
-                        DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
-                        leaveAllSystemAppsEnabled)
-                .setPackage(getManagedProvisioningPackage(mContext))
-                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
-
         final long id = mInjector.binderClearCallingIdentity();
         try {
             manageUserUnchecked(admin, profileOwner, userHandle, adminExtras,
@@ -10672,6 +10663,9 @@
                         Settings.Secure.USER_SETUP_COMPLETE, 1, userHandle);
             }
 
+            sendProvisioningCompletedBroadcast(
+                    userHandle, ACTION_PROVISION_MANAGED_USER, leaveAllSystemAppsEnabled);
+
             return user;
         } catch (Throwable re) {
             mUserManager.removeUser(userHandle);
@@ -10686,6 +10680,20 @@
         }
     }
 
+    private void sendProvisioningCompletedBroadcast(
+            int user, String action, boolean leaveAllSystemAppsEnabled) {
+        final Intent intent = new Intent(DevicePolicyManager.ACTION_PROVISIONING_COMPLETED)
+                .putExtra(Intent.EXTRA_USER_HANDLE, user)
+                .putExtra(
+                        DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
+                        leaveAllSystemAppsEnabled)
+                .putExtra(DevicePolicyManager.EXTRA_PROVISIONING_ACTION,
+                        action)
+                .setPackage(getManagedProvisioningPackage(mContext))
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+    }
+
     private void manageUserUnchecked(ComponentName admin, ComponentName profileOwner,
             @UserIdInt int userId, @Nullable PersistableBundle adminExtras,
             boolean showDisclaimer) {
@@ -17230,7 +17238,7 @@
                     ACTION_PROVISION_MANAGED_PROFILE, admin.getPackageName());
             if (result != CODE_OK) {
                 throw new ServiceSpecificException(
-                        PROVISIONING_RESULT_PRE_CONDITION_FAILED,
+                        ERROR_PRE_CONDITION_FAILED,
                         "Provisioning preconditions failed with result: " + result);
             }
 
@@ -17247,7 +17255,7 @@
                     nonRequiredApps.toArray(new String[nonRequiredApps.size()]));
             if (userInfo == null) {
                 throw new ServiceSpecificException(
-                        PROVISIONING_RESULT_PROFILE_CREATION_FAILED,
+                        ERROR_PROFILE_CREATION_FAILED,
                         "Error creating profile, createProfileForUserEvenWhenDisallowed "
                                 + "returned null.");
             }
@@ -17261,7 +17269,7 @@
             if (!enableAdminAndSetProfileOwner(
                     userInfo.id, caller.getUserId(), admin, provisioningParams.getOwnerName())) {
                 throw new ServiceSpecificException(
-                        PROVISIONING_RESULT_SETTING_PROFILE_OWNER_FAILED,
+                        ERROR_SETTING_PROFILE_OWNER_FAILED,
                         "Error setting profile owner.");
             }
             setUserSetupComplete(userInfo.id);
@@ -17269,7 +17277,7 @@
             startUser(userInfo.id, callerPackage);
             maybeMigrateAccount(
                     userInfo.id, caller.getUserId(), provisioningParams.getAccountToMigrate(),
-                    provisioningParams.isKeepAccountMigrated(), callerPackage);
+                    provisioningParams.isKeepingAccountOnMigration(), callerPackage);
 
             if (provisioningParams.isOrganizationOwnedProvisioning()) {
                 synchronized (getLockObject()) {
@@ -17277,6 +17285,11 @@
                 }
             }
 
+            sendProvisioningCompletedBroadcast(
+                    userInfo.id,
+                    ACTION_PROVISION_MANAGED_PROFILE,
+                    provisioningParams.isLeaveAllSystemAppsEnabled());
+
             return userInfo.getUserHandle();
         } catch (Exception e) {
             DevicePolicyEventLogger
@@ -17336,14 +17349,14 @@
                     userId);
             if (status != PackageManager.INSTALL_SUCCEEDED) {
                 throw new ServiceSpecificException(
-                        PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED,
+                        ERROR_ADMIN_PACKAGE_INSTALLATION_FAILED,
                         String.format("Failed to install existing package %s for user %d with "
                                         + "result code %d",
                                 packageName, userId, status));
             }
         } catch (NameNotFoundException e) {
             throw new ServiceSpecificException(
-                    PROVISIONING_RESULT_ADMIN_PACKAGE_INSTALLATION_FAILED,
+                    ERROR_ADMIN_PACKAGE_INSTALLATION_FAILED,
                     String.format("Failed to install existing package %s for user %d: %s",
                             packageName, userId, e.getMessage()));
         }
@@ -17401,12 +17414,12 @@
                 /* scheduler= */ null);
         try {
             if (!mInjector.getIActivityManager().startUserInBackground(userId)) {
-                throw new ServiceSpecificException(PROVISIONING_RESULT_STARTING_PROFILE_FAILED,
+                throw new ServiceSpecificException(ERROR_STARTING_PROFILE_FAILED,
                         String.format("Unable to start user %d in background", userId));
             }
 
             if (!unlockedReceiver.waitForUserUnlocked()) {
-                throw new ServiceSpecificException(PROVISIONING_RESULT_STARTING_PROFILE_FAILED,
+                throw new ServiceSpecificException(ERROR_STARTING_PROFILE_FAILED,
                         String.format("Timeout whilst waiting for unlock of user %d.", userId));
             }
             logEventDuration(
@@ -17529,7 +17542,7 @@
                     ACTION_PROVISION_MANAGED_DEVICE, deviceAdmin.getPackageName());
             if (result != CODE_OK) {
                 throw new ServiceSpecificException(
-                        PROVISIONING_RESULT_PRE_CONDITION_FAILED,
+                        ERROR_PRE_CONDITION_FAILED,
                         "Provisioning preconditions failed with result: " + result);
             }
             setTimeAndTimezone(provisioningParams.getTimeZone(), provisioningParams.getLocalTime());
@@ -17542,7 +17555,7 @@
                     provisioningParams.isLeaveAllSystemAppsEnabled(),
                     deviceAdmin)) {
                 throw new ServiceSpecificException(
-                        PROVISIONING_RESULT_REMOVE_NON_REQUIRED_APPS_FAILED,
+                        ERROR_REMOVE_NON_REQUIRED_APPS_FAILED,
                         "PackageManager failed to remove non required apps.");
             }
 
@@ -17550,13 +17563,17 @@
             if (!setActiveAdminAndDeviceOwner(
                     deviceOwnerUserId, deviceAdmin, provisioningParams.getOwnerName())) {
                 throw new ServiceSpecificException(
-                        PROVISIONING_RESULT_SET_DEVICE_OWNER_FAILED,
+                        ERROR_SET_DEVICE_OWNER_FAILED,
                         "Failed to set device owner.");
             }
 
             disallowAddUser();
             setAdminCanGrantSensorsPermissionForUserUnchecked(deviceOwnerUserId,
                     provisioningParams.canDeviceOwnerGrantSensorsPermissions());
+            sendProvisioningCompletedBroadcast(
+                    deviceOwnerUserId,
+                    ACTION_PROVISION_MANAGED_DEVICE,
+                    provisioningParams.isLeaveAllSystemAppsEnabled());
         } catch (Exception e) {
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.PLATFORM_PROVISIONING_ERROR)
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a72cf3a..45d9626 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -332,6 +332,8 @@
             "com.android.server.contentcapture.ContentCaptureManagerService";
     private static final String TRANSLATION_MANAGER_SERVICE_CLASS =
             "com.android.server.translation.TranslationManagerService";
+    private static final String SELECTION_TOOLBAR_MANAGER_SERVICE_CLASS =
+            "com.android.server.selectiontoolbar.SelectionToolbarManagerService";
     private static final String MUSIC_RECOGNITION_MANAGER_SERVICE_CLASS =
             "com.android.server.musicrecognition.MusicRecognitionManagerService";
     private static final String SYSTEM_CAPTIONS_MANAGER_SERVICE_CLASS =
@@ -2592,6 +2594,11 @@
             Slog.d(TAG, "TranslationService not defined by OEM");
         }
 
+        // Selection toolbar service
+        t.traceBegin("StartSelectionToolbarManagerService");
+        mSystemServiceManager.startService(SELECTION_TOOLBAR_MANAGER_SERVICE_CLASS);
+        t.traceEnd();
+
         // NOTE: ClipboardService depends on ContentCapture and Autofill
         t.traceBegin("StartClipboardService");
         mSystemServiceManager.startService(ClipboardService.class);
diff --git a/services/selectiontoolbar/Android.bp b/services/selectiontoolbar/Android.bp
new file mode 100644
index 0000000..cc6405f
--- /dev/null
+++ b/services/selectiontoolbar/Android.bp
@@ -0,0 +1,22 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "services.selectiontoolbar-sources",
+    srcs: ["java/**/*.java"],
+    path: "java",
+    visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+    name: "services.selectiontoolbar",
+    defaults: ["platform_service_defaults"],
+    srcs: [":services.selectiontoolbar-sources"],
+    libs: ["services.core"],
+}
diff --git a/services/selectiontoolbar/OWNERS b/services/selectiontoolbar/OWNERS
new file mode 100644
index 0000000..ed9425c
--- /dev/null
+++ b/services/selectiontoolbar/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/selectiontoolbar/OWNERS
diff --git a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerService.java b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerService.java
new file mode 100644
index 0000000..3bdf55c
--- /dev/null
+++ b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerService.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 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.selectiontoolbar;
+
+import android.content.Context;
+import android.util.Slog;
+import android.view.selectiontoolbar.ISelectionToolbarCallback;
+import android.view.selectiontoolbar.ISelectionToolbarManager;
+import android.view.selectiontoolbar.ShowInfo;
+
+import com.android.internal.util.DumpUtils;
+import com.android.server.infra.AbstractMasterSystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Entry point service for selection toolbar management.
+ */
+public final class SelectionToolbarManagerService extends
+        AbstractMasterSystemService<SelectionToolbarManagerService,
+                SelectionToolbarManagerServiceImpl> {
+
+    private static final String TAG = "SelectionToolbarManagerService";
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.SELECTION_TOOLBAR_SERVICE,
+                new SelectionToolbarManagerService.SelectionToolbarManagerServiceStub());
+    }
+
+    public SelectionToolbarManagerService(Context context) {
+        super(context, new SelectionToolbarServiceNameResolver(), /* disallowProperty= */
+                null, PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
+    }
+
+    @Override
+    protected SelectionToolbarManagerServiceImpl newServiceLocked(int resolvedUserId,
+            boolean disabled) {
+        return new SelectionToolbarManagerServiceImpl(this, mLock, resolvedUserId);
+    }
+
+    final class SelectionToolbarManagerServiceStub extends ISelectionToolbarManager.Stub {
+
+        @Override
+        public void showToolbar(ShowInfo showInfo, ISelectionToolbarCallback callback, int userId) {
+            synchronized (mLock) {
+                SelectionToolbarManagerServiceImpl service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.showToolbar(showInfo, callback);
+                } else {
+                    Slog.v(TAG, "showToolbar(): no service for " + userId);
+                }
+            }
+        }
+
+        @Override
+        public void hideToolbar(long widgetToken, int userId) {
+            synchronized (mLock) {
+                SelectionToolbarManagerServiceImpl service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.hideToolbar(widgetToken);
+                } else {
+                    Slog.v(TAG, "hideToolbar(): no service for " + userId);
+                }
+            }
+        }
+
+        @Override
+        public void dismissToolbar(long widgetToken, int userId) {
+            synchronized (mLock) {
+                SelectionToolbarManagerServiceImpl service = getServiceForUserLocked(userId);
+                if (service != null) {
+                    service.dismissToolbar(widgetToken);
+                } else {
+                    Slog.v(TAG, "dismissToolbar(): no service for " + userId);
+                }
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
+
+            synchronized (mLock) {
+                dumpLocked("", pw);
+            }
+        }
+    }
+}
diff --git a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerServiceImpl.java b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerServiceImpl.java
new file mode 100644
index 0000000..94bf712
--- /dev/null
+++ b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarManagerServiceImpl.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 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.selectiontoolbar;
+
+import android.annotation.NonNull;
+import android.view.selectiontoolbar.ISelectionToolbarCallback;
+import android.view.selectiontoolbar.ShowInfo;
+
+import com.android.server.infra.AbstractPerUserSystemService;
+
+final class SelectionToolbarManagerServiceImpl extends
+        AbstractPerUserSystemService<SelectionToolbarManagerServiceImpl,
+                SelectionToolbarManagerService> {
+
+    private static final String TAG = "SelectionToolbarManagerServiceImpl";
+
+    protected SelectionToolbarManagerServiceImpl(@NonNull SelectionToolbarManagerService master,
+            @NonNull Object lock, int userId) {
+        super(master, lock, userId);
+    }
+
+    void showToolbar(ShowInfo showInfo, ISelectionToolbarCallback callback) {
+        // TODO: add implementation to bind service
+    }
+
+    void hideToolbar(long widgetToken) {
+        // TODO: add implementation to bind service
+    }
+
+    void dismissToolbar(long widgetToken) {
+        // TODO: add implementation to bind service
+    }
+}
diff --git a/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarServiceNameResolver.java b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarServiceNameResolver.java
new file mode 100644
index 0000000..1d4c94d
--- /dev/null
+++ b/services/selectiontoolbar/java/com/android/server/selectiontoolbar/SelectionToolbarServiceNameResolver.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 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.selectiontoolbar;
+
+import com.android.server.infra.ServiceNameResolver;
+
+import java.io.PrintWriter;
+
+final class SelectionToolbarServiceNameResolver implements ServiceNameResolver {
+
+    // TODO: move to SysUi or ExtServices
+    private static final String SELECTION_TOOLBAR_SERVICE_NAME =
+            "android/com.android.server.selectiontoolbar.DefaultSelectionToolbarRenderService";
+
+    @Override
+    public String getDefaultServiceName(int userId) {
+        return SELECTION_TOOLBAR_SERVICE_NAME;
+    }
+
+    @Override
+    public void dumpShort(PrintWriter pw) {
+        pw.print("service="); pw.print(SELECTION_TOOLBAR_SERVICE_NAME);
+    }
+
+    @Override
+    public void dumpShort(PrintWriter pw, int userId) {
+        pw.print("defaultService="); pw.print(getDefaultServiceName(userId));
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 3e617d5..55d6df9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -34,6 +34,7 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
 import android.app.KeyguardManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
@@ -58,6 +59,7 @@
 import com.android.server.LocalServices;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.pm.PackageManagerService;
+import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptResult;
 
 import org.junit.After;
 import org.junit.Before;
@@ -298,35 +300,44 @@
         assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
     }
 
-    public void addMockInterceptorCallback(@Nullable Intent intent) {
+    public void addMockInterceptorCallback(
+            @Nullable Intent intent, @Nullable ActivityOptions activityOptions) {
         int size = mActivityInterceptorCallbacks.size();
         mActivityInterceptorCallbacks.put(size, new ActivityInterceptorCallback() {
             @Override
-            public Intent intercept(ActivityInterceptorInfo info) {
-                return intent;
+            public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
+                if (intent == null && activityOptions == null) {
+                    return null;
+                }
+                return new ActivityInterceptResult(
+                        intent != null ? intent : info.intent,
+                        activityOptions != null ? activityOptions : info.checkedOptions);
             }
         });
     }
 
     @Test
     public void testInterceptionCallback_singleCallback() {
-        addMockInterceptorCallback(new Intent("android.test.foo"));
+        addMockInterceptorCallback(
+                new Intent("android.test.foo"),
+                ActivityOptions.makeBasic().setLaunchDisplayId(3));
 
         assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
         assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
+        assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
     }
 
     @Test
     public void testInterceptionCallback_singleCallbackReturnsNull() {
-        addMockInterceptorCallback(null);
+        addMockInterceptorCallback(null, null);
 
         assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
     }
 
     @Test
     public void testInterceptionCallback_fallbackToSecondCallback() {
-        addMockInterceptorCallback(null);
-        addMockInterceptorCallback(new Intent("android.test.second"));
+        addMockInterceptorCallback(null, null);
+        addMockInterceptorCallback(new Intent("android.test.second"), null);
 
         assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
         assertEquals("android.test.second", mInterceptor.mIntent.getAction());
@@ -334,7 +345,7 @@
 
     @Test
     public void testActivityLaunchedCallback_singleCallback() {
-        addMockInterceptorCallback(null);
+        addMockInterceptorCallback(null, null);
 
         assertEquals(1, mActivityInterceptorCallbacks.size());
         final ActivityInterceptorCallback callback = mActivityInterceptorCallbacks.valueAt(0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index e0072b4..a2b04c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -53,7 +53,6 @@
 import android.app.PictureInPictureParams;
 import android.app.servertransaction.ClientTransaction;
 import android.app.servertransaction.EnterPipRequestedItem;
-import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
@@ -951,7 +950,7 @@
                 new ActivityInterceptorCallback() {
                     @Nullable
                     @Override
-                    public Intent intercept(ActivityInterceptorInfo info) {
+                    public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
                         return null;
                     }
                 });
@@ -963,7 +962,7 @@
                 new ActivityInterceptorCallback() {
                     @Nullable
                     @Override
-                    public Intent intercept(ActivityInterceptorInfo info) {
+                    public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
                         return null;
                     }
                 });
@@ -975,7 +974,7 @@
                 new ActivityInterceptorCallback() {
                     @Nullable
                     @Override
-                    public Intent intercept(ActivityInterceptorInfo info) {
+                    public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
                         return null;
                     }
                 });
@@ -983,7 +982,7 @@
                 new ActivityInterceptorCallback() {
                     @Nullable
                     @Override
-                    public Intent intercept(ActivityInterceptorInfo info) {
+                    public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
                         return null;
                     }
                 });
@@ -997,7 +996,7 @@
                 new ActivityInterceptorCallback() {
                     @Nullable
                     @Override
-                    public Intent intercept(ActivityInterceptorInfo info) {
+                    public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
                         return null;
                     }
                 });
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index a97c057..ec6cd92 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -525,6 +525,43 @@
     }
 
     @Test
+    public void testAppTransitionWithRotationChange() {
+        final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, "statusBar");
+        makeWindowVisible(statusBar);
+        mDisplayContent.getDisplayPolicy().addWindowLw(statusBar, statusBar.mAttrs);
+        final ActivityRecord app = createActivityRecord(mDisplayContent);
+        final TestTransitionPlayer player = registerTestTransitionPlayer();
+        final Transition transition = app.mTransitionController.createTransition(TRANSIT_OPEN);
+        app.mTransitionController.requestStartTransition(transition, app.getTask(),
+                null /* remoteTransition */, null /* displayChange */);
+        mDisplayContent.getDisplayRotation().setRotation(mDisplayContent.getRotation() + 1);
+        final int anyChanges = 1;
+        mDisplayContent.requestChangeTransitionIfNeeded(anyChanges, null /* displayChange */);
+        transition.setKnownConfigChanges(mDisplayContent, anyChanges);
+        final FadeRotationAnimationController fadeController =
+                mDisplayContent.getFadeRotationAnimationController();
+        assertNotNull(fadeController);
+        assertTrue(fadeController.shouldFreezeInsetsPosition(statusBar));
+
+        statusBar.setOrientationChanging(true);
+        player.startTransition();
+        // Non-app windows should not be collected.
+        assertFalse(statusBar.mToken.inTransition());
+        assertTrue(app.getTask().inTransition());
+
+        final SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class);
+        player.onTransactionReady(startTransaction);
+        // The leash should be unrotated.
+        verify(startTransaction).setMatrix(eq(statusBar.mToken.getAnimationLeash()), any(), any());
+
+        // The redrawn window will be faded in when the transition finishes. And because this test
+        // only use one non-activity window, the fade rotation controller should also be cleared.
+        statusBar.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+        player.finish();
+        assertNull(mDisplayContent.getFadeRotationAnimationController());
+    }
+
+    @Test
     public void testIntermediateVisibility() {
         final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
         final TransitionController controller = new TransitionController(mAtm, snapshotController);
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 2d3b928..88725a6 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -552,23 +552,26 @@
         private static final int MSG_PACKAGE_REMOVED = 103;
         /**
          * By only triggering a re-calculation after the storage has changed sizes, we can avoid
-         * recalculating quotas too often. Minimum change delta defines the percentage of change
-         * we need to see before we recalculate.
+         * recalculating quotas too often. Minimum change delta high and low define the
+         * percentage of change we need to see before we recalculate quotas when the device has
+         * enough storage space (more than StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total
+         * free) and in low storage condition respectively.
          */
-        private static final double MINIMUM_CHANGE_DELTA = 0.05;
+        private static final long MINIMUM_CHANGE_DELTA_PERCENT_HIGH = 5;
+        private static final long MINIMUM_CHANGE_DELTA_PERCENT_LOW = 2;
         private static final int UNSET = -1;
         private static final boolean DEBUG = false;
 
         private final StatFs mStats;
         private long mPreviousBytes;
-        private double mMinimumThresholdBytes;
+        private long mTotalBytes;
 
         public H(Looper looper) {
             super(looper);
             // TODO: Handle all private volumes.
             mStats = new StatFs(Environment.getDataDirectory().getAbsolutePath());
             mPreviousBytes = mStats.getAvailableBytes();
-            mMinimumThresholdBytes = mStats.getTotalBytes() * MINIMUM_CHANGE_DELTA;
+            mTotalBytes = mStats.getTotalBytes();
         }
 
         public void handleMessage(Message msg) {
@@ -584,7 +587,14 @@
                 case MSG_CHECK_STORAGE_DELTA: {
                     mStats.restat(Environment.getDataDirectory().getAbsolutePath());
                     long bytesDelta = Math.abs(mPreviousBytes - mStats.getAvailableBytes());
-                    if (bytesDelta > mMinimumThresholdBytes) {
+                    long bytesDeltaThreshold;
+                    if (mStats.getAvailableBytes() >  mTotalBytes
+                            * StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH / 100) {
+                        bytesDeltaThreshold = mTotalBytes * MINIMUM_CHANGE_DELTA_PERCENT_HIGH / 100;
+                    } else {
+                        bytesDeltaThreshold = mTotalBytes * MINIMUM_CHANGE_DELTA_PERCENT_LOW / 100;
+                    }
+                    if (bytesDelta > bytesDeltaThreshold) {
                         mPreviousBytes = mStats.getAvailableBytes();
                         recalculateQuotas(getInitializedStrategy());
                         notifySignificantDelta();
diff --git a/telephony/java/android/service/carrier/CarrierService.java b/telephony/java/android/service/carrier/CarrierService.java
index d06ec11..ae91d4d 100644
--- a/telephony/java/android/service/carrier/CarrierService.java
+++ b/telephony/java/android/service/carrier/CarrierService.java
@@ -15,6 +15,8 @@
 package android.service.carrier;
 
 import android.annotation.CallSuper;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
@@ -22,9 +24,12 @@
 import android.os.IBinder;
 import android.os.PersistableBundle;
 import android.os.ResultReceiver;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyRegistryManager;
 import android.util.Log;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
@@ -87,7 +92,54 @@
      * PersistableBundle} may be overridden by the system's default configuration service.
      * </p>
      *
-     * @param id contains details about the current carrier that can be used do decide what
+     * @param id contains details about the current carrier that can be used to decide what
+     *           configuration values to return. Instead of using details like MCCMNC to decide
+     *           current carrier, it also contains subscription carrier id
+     *           {@link android.telephony.TelephonyManager#getSimCarrierId()}, a platform-wide
+     *           unique identifier for each carrier, CarrierConfigService can directly use carrier
+     *           id as the key to look up the carrier info.
+     * @return a {@link PersistableBundle} object containing the configuration or null if default
+     *         values should be used.
+     * @deprecated use {@link #onLoadConfig(int, CarrierIdentifier)} instead.
+     */
+    @Deprecated
+    public abstract PersistableBundle onLoadConfig(CarrierIdentifier id);
+
+    /**
+     * Override this method to set carrier configuration on the given {@code subscriptionId}.
+     * <p>
+     * This method will be called by telephony services to get carrier-specific configuration
+     * values. The returned config will be saved by the system until,
+     * <ol>
+     * <li>The carrier app package is updated, or</li>
+     * <li>The carrier app requests a reload with
+     * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId
+     * notifyConfigChangedForSubId}.</li>
+     * </ol>
+     * This method can be called after a SIM card loads, which may be before or after boot.
+     * </p>
+     * <p>
+     * This method should not block for a long time. If expensive operations (e.g. network access)
+     * are required, this method can schedule the work and return null. Then, use
+     * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId
+     * notifyConfigChangedForSubId} to trigger a reload when the config is ready.
+     * </p>
+     * <p>
+     * Implementations should use the keys defined in {@link android.telephony.CarrierConfigManager
+     * CarrierConfigManager}. Any configuration values not set in the returned {@link
+     * PersistableBundle} may be overridden by the system's default configuration service.
+     * </p>
+     * <p>
+     * By default, this method just calls {@link #onLoadConfig(CarrierIdentifier)} with specified
+     * CarrierIdentifier {@code id}. Carrier app with target SDK
+     * {@link android.os.Build.VERSION_CODES#TIRAMISU} and above should override this method to
+     * load carrier configuration on the given {@code subscriptionId}.
+     * Note that {@link #onLoadConfig(CarrierIdentifier)} is still called prior to
+     * {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+     * </p>
+     *
+     * @param subscriptionId the subscription on which the carrier app should load configuration
+     * @param id contains details about the current carrier that can be used to decide what
      *           configuration values to return. Instead of using details like MCCMNC to decide
      *           current carrier, it also contains subscription carrier id
      *           {@link android.telephony.TelephonyManager#getSimCarrierId()}, a platform-wide
@@ -96,7 +148,11 @@
      * @return a {@link PersistableBundle} object containing the configuration or null if default
      *         values should be used.
      */
-    public abstract PersistableBundle onLoadConfig(CarrierIdentifier id);
+    @SuppressLint("NullableCollection")
+    @Nullable
+    public PersistableBundle onLoadConfig(int subscriptionId, @Nullable CarrierIdentifier id) {
+        return onLoadConfig(id);
+    }
 
     /**
      * Informs the system of an intentional upcoming carrier network change by
@@ -115,7 +171,12 @@
      *               active. Set this value to true to begin showing
      *               alternative UI and false to stop.
      * @see android.telephony.TelephonyManager#hasCarrierPrivileges
+     * @deprecated use {@link #notifyCarrierNetworkChange(int, boolean)} instead.
+     *             With no parameter to specify the subscription, this API will
+     *             apply to all subscriptions that the carrier app has carrier
+     *             privileges on.
      */
+    @Deprecated
     public final void notifyCarrierNetworkChange(boolean active) {
         TelephonyRegistryManager telephonyRegistryMgr =
             (TelephonyRegistryManager) this.getSystemService(
@@ -126,6 +187,31 @@
     }
 
     /**
+     * Informs the system of an intentional upcoming carrier network change by a carrier app on the
+     * given {@code subscriptionId}. This call is optional and is only used to allow the system to
+     * provide alternative UI while telephony is performing an action that may result in
+     * intentional, temporary network lack of connectivity.
+     *
+     * <p>Based on the active parameter passed in, this method will either show or hide the
+     * alternative UI. There is no timeout associated with showing this UX, so a carrier app must
+     * be sure to call with active set to false sometime after calling with it set to true.
+     *
+     * <p>Requires Permission: calling app has carrier privileges.
+     *
+     * @param subscriptionId the subscription of the carrier network that trigger the change.
+     * @param active whether the carrier network change is or shortly will be active. Set this
+     *               value to true to begin showing alternative UI and false to stop.
+     * @see android.telephony.TelephonyManager#hasCarrierPrivileges
+     */
+    public final void notifyCarrierNetworkChange(int subscriptionId, boolean active) {
+        TelephonyRegistryManager telephonyRegistryMgr = this.getSystemService(
+                TelephonyRegistryManager.class);
+        if (telephonyRegistryMgr != null) {
+            telephonyRegistryMgr.notifyCarrierNetworkChange(subscriptionId, active);
+        }
+    }
+
+    /**
      * If overriding this method, call through to the super method for any unknown actions.
      * {@inheritDoc}
      */
@@ -149,10 +235,16 @@
         public static final String KEY_CONFIG_BUNDLE = "config_bundle";
 
         @Override
-        public void getCarrierConfig(CarrierIdentifier id, ResultReceiver result) {
+        public void getCarrierConfig(int phoneId, CarrierIdentifier id, ResultReceiver result) {
             try {
+                int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                int[] subIds = SubscriptionManager.getSubId(phoneId);
+                if (!ArrayUtils.isEmpty(subIds)) {
+                    // There should be at most one active subscription mapping to the phoneId.
+                    subId = subIds[0];
+                }
                 Bundle data = new Bundle();
-                data.putParcelable(KEY_CONFIG_BUNDLE, CarrierService.this.onLoadConfig(id));
+                data.putParcelable(KEY_CONFIG_BUNDLE, CarrierService.this.onLoadConfig(subId, id));
                 result.send(RESULT_OK, data);
             } catch (Exception e) {
                 Log.e(LOG_TAG, "Error in onLoadConfig: " + e.getMessage(), e);
diff --git a/telephony/java/android/service/carrier/ICarrierService.aidl b/telephony/java/android/service/carrier/ICarrierService.aidl
index ac6f9614..054a280 100644
--- a/telephony/java/android/service/carrier/ICarrierService.aidl
+++ b/telephony/java/android/service/carrier/ICarrierService.aidl
@@ -29,5 +29,5 @@
 interface ICarrierService {
 
     /** @see android.service.carrier.CarrierService#onLoadConfig */
-    oneway void getCarrierConfig(in CarrierIdentifier id, in ResultReceiver result);
+    oneway void getCarrierConfig(in int phoneId, in CarrierIdentifier id, in ResultReceiver result);
 }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c80d35b..4bfb2d8 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3776,6 +3776,17 @@
             "esim_max_download_retry_attempts_int";
 
     /**
+     * List of opportunistic carrier-ids associated with CBRS Primary SIM. When CBRS pSIM is
+     * inserted, opportunistic eSIM is download and this configuration is used for grouping pSIM
+     * and opportunistic eSIM. Also when a new CBRS pSIM is inserted, old opportunistic eSIMs are
+     * deleted using the carrier-ids in this configuration.
+     *
+     * @hide
+     */
+    public static final String KEY_OPPORTUNISTIC_CARRIER_IDS_INT_ARRAY =
+            "opportunistic_carrier_ids_int_array";
+
+    /**
      * Controls RSRP threshold at which OpportunisticNetworkService will decide whether
      * the opportunistic network is good enough for internet data.
      */
@@ -5934,6 +5945,7 @@
         sDefaults.putString(KEY_SMDP_SERVER_ADDRESS_STRING, "");
         sDefaults.putInt(KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 5);
         sDefaults.putInt(KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 60);
+        sDefaults.putIntArray(KEY_OPPORTUNISTIC_CARRIER_IDS_INT_ARRAY, new int[] {0});
         /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
         sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
         /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
index 9cb80f1..4884d54 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -130,7 +131,10 @@
         /**
          * Set the builder object if require reporting on the system thresholds when device is idle.
          *
-         * <p>This can only used by the system caller. Requires permission
+         * <p>This is intended to be used by the system privileged caller only. When setting to
+         * {@code true}, signal strength update request through
+         * {@link TelephonyManager#setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)}
+         * will require permission
          * {@link android.Manifest.permission#LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH}.
          *
          * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the
@@ -138,6 +142,7 @@
          * @return the builder to facilitate the chaining
          * @hide
          */
+        @SystemApi
         @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
         public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle(
                 boolean isSystemThresholdReportingRequestedWhileIdle) {
@@ -191,6 +196,7 @@
      *
      * @hide
      */
+    @SystemApi
     public boolean isSystemThresholdReportingRequestedWhileIdle() {
         return mIsSystemThresholdReportingRequestedWhileIdle;
     }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index f728324..821b74a 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -941,6 +941,13 @@
     public static final String PROFILE_CLASS = SimInfo.COLUMN_PROFILE_CLASS;
 
     /**
+     * TelephonyProvider column name for the port index of the active UICC port.
+     * <P>Type: INTEGER (int)</P>
+     * @hide
+     */
+    public static final String PORT_INDEX = SimInfo.COLUMN_PORT_INDEX;
+
+    /**
      * TelephonyProvider column name for VoIMS opt-in status.
      *
      * <P>Type: INTEGER (int)</P>
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index cca5e2f..7f10d64 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -70,6 +70,7 @@
 import android.os.WorkSource;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.carrier.CarrierIdentifier;
+import android.service.carrier.CarrierService;
 import android.sysprop.TelephonyProperties;
 import android.telecom.CallScreeningService;
 import android.telecom.InCallService;
@@ -320,11 +321,19 @@
     public static final int UNINITIALIZED_CARD_ID = -2;
 
     /**
-     * Default port index for the UICC Card
-     * @hide
+     * Default port index for a UICC.
+     *
+     * On physical SIM cards the only available port is 0.
+     * See {@link android.telephony.UiccPortInfo} for more information on ports.
+     *
+     * See {@link android.telephony.euicc.EuiccManager#isSimPortAvailable(int)} for information on
+     * how portIndex is used on eUICCs.
      */
     public static final int DEFAULT_PORT_INDEX = 0;
 
+    /** @hide */
+    public static final int INVALID_PORT_INDEX = -1;
+
     private final Context mContext;
     private final int mSubId;
     @UnsupportedAppUsage
@@ -9408,6 +9417,57 @@
         return null;
     }
 
+    /**
+     * Returns the package name that provides the {@link CarrierService} implementation for the
+     * current subscription, or {@code null} if no package with carrier privileges declares one.
+     *
+     * <p>If this object has been created with {@link #createForSubscriptionId}, then the provided
+     * subscription ID is used. Otherwise, the default subscription ID will be used.
+     *
+     * @return The system-selected package that provides the {@link CarrierService} implementation
+     * for the current subscription, or {@code null} if none is resolved
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @Nullable String getCarrierServicePackageName() {
+        // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
+        // value instead of re-querying every time.
+        List<String> carrierServicePackages =
+                getCarrierPackageNamesForIntent(
+                        new Intent(CarrierService.CARRIER_SERVICE_INTERFACE));
+        if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
+            return carrierServicePackages.get(0);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the package name that provides the {@link CarrierService} implementation for the
+     * specified {@code logicalSlotIndex}, or {@code null} if no package with carrier privileges
+     * declares one.
+     *
+     * @param logicalSlotIndex The slot index to fetch the {@link CarrierService} package for
+     * @return The system-selected package that provides the {@link CarrierService} implementation
+     * for the slot, or {@code null} if none is resolved
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @Nullable String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) {
+        // TODO(b/205736323) plumb this through to CarrierPrivilegesTracker, which will cache the
+        // value instead of re-querying every time.
+        List<String> carrierServicePackages =
+                getCarrierPackageNamesForIntentAndPhone(
+                        new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), logicalSlotIndex);
+        if (carrierServicePackages != null && !carrierServicePackages.isEmpty()) {
+            return carrierServicePackages.get(0);
+        }
+        return null;
+    }
+
     /** @hide */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public List<String> getPackagesWithCarrierPrivileges() {
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index ab35d77..885244e 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -66,14 +66,15 @@
 
     /** Reason for canceling a profile download session */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "CANCEL_REASON_" }, value = {
+    @IntDef(prefix = {"CANCEL_REASON_"}, value = {
             CANCEL_REASON_END_USER_REJECTED,
             CANCEL_REASON_POSTPONED,
             CANCEL_REASON_TIMEOUT,
             CANCEL_REASON_PPR_NOT_ALLOWED
     })
     /** @hide */
-    public @interface CancelReason {}
+    public @interface CancelReason {
+    }
 
     /**
      * The end user has rejected the download. The profile will be put into the error state and
@@ -96,13 +97,14 @@
 
     /** Options for resetting eUICC memory */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, prefix = { "RESET_OPTION_" }, value = {
+    @IntDef(flag = true, prefix = {"RESET_OPTION_"}, value = {
             RESET_OPTION_DELETE_OPERATIONAL_PROFILES,
             RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES,
             RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS
     })
     /** @hide */
-    public @interface ResetOption {}
+    public @interface ResetOption {
+    }
 
     /** Deletes all operational profiles. */
     public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1;
@@ -124,6 +126,10 @@
 
     /** Result code indicating the caller is not the active LPA. */
     public static final int RESULT_CALLER_NOT_ALLOWED = -3;
+
+    /** Result code when the requested profile is not found */
+    public static final int RESULT_PROFILE_NOT_FOUND = -4;
+
     /**
      * Callback to receive the result of an eUICC card API.
      *
@@ -134,9 +140,9 @@
          * This method will be called when an eUICC card API call is completed.
          *
          * @param resultCode This can be {@link #RESULT_OK} or other positive values returned by the
-         *     eUICC.
-         * @param result The result object. It can be null if the {@code resultCode} is not
-         *     {@link #RESULT_OK}.
+         *                   eUICC.
+         * @param result     The result object. It can be null if the {@code resultCode} is not
+         *                   {@link #RESULT_OK}.
          */
         void onComplete(int resultCode, T result);
     }
@@ -159,7 +165,7 @@
     /**
      * Requests all the profiles on eUicc.
      *
-     * @param cardId The Id of the eUICC.
+     * @param cardId   The Id of the eUICC.
      * @param executor The executor through which the callback should be invoked.
      * @param callback The callback to get the result code and all the profiles.
      */
@@ -187,8 +193,8 @@
     /**
      * Requests the profile of the given iccid.
      *
-     * @param cardId The Id of the eUICC.
-     * @param iccid The iccid of the profile.
+     * @param cardId   The Id of the eUICC.
+     * @param iccid    The iccid of the profile.
      * @param executor The executor through which the callback should be invoked.
      * @param callback The callback to get the result code and profile.
      */
@@ -214,16 +220,47 @@
     }
 
     /**
+     * Requests the enabled profile for a given port on an eUicc.
+     *
+     * @param cardId    The Id of the eUICC.
+     * @param portIndex The portIndex to use. The port may be active or inactive. As long as the
+     *                  ICCID is known, an APDU will be sent through to read the enabled profile.
+     * @param executor  The executor through which the callback should be invoked.
+     * @param callback  The callback to get the result code and the profile.
+     */
+    public void requestEnabledProfileForPort(@NonNull String cardId, int portIndex,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull ResultCallback<EuiccProfileInfo> callback) {
+        try {
+            getIEuiccCardController().getEnabledProfile(mContext.getOpPackageName(), cardId,
+                    portIndex,
+                    new IGetProfileCallback.Stub() {
+                        @Override
+                        public void onComplete(int resultCode, EuiccProfileInfo profile) {
+                            final long token = Binder.clearCallingIdentity();
+                            try {
+                                executor.execute(() -> callback.onComplete(resultCode, profile));
+                            } finally {
+                                Binder.restoreCallingIdentity(token);
+                            }
+                        }
+                    });
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling requestEnabledProfileForPort", e);
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Disables the profile of the given iccid.
      *
-     * @param cardId The Id of the eUICC.
-     * @param iccid The iccid of the profile.
-     * @param refresh Whether sending the REFRESH command to modem.
+     * @param cardId   The Id of the eUICC.
+     * @param iccid    The iccid of the profile.
+     * @param refresh  Whether sending the REFRESH command to modem.
      * @param executor The executor through which the callback should be invoked.
      * @param callback The callback to get the result code.
-     *
      * @deprecated instead use {@link #disableProfile(String, String, int, boolean, Executor,
-     *             ResultCallback)}
+     * ResultCallback)}
      */
     @Deprecated
     public void disableProfile(String cardId, String iccid, boolean refresh,
@@ -247,15 +284,16 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
     /**
      * Disables the profile of the given ICCID.
      *
-     * @param cardId The Id of the eUICC.
-     * @param iccid The iccid of the profile.
+     * @param cardId    The Id of the eUICC.
+     * @param iccid     The iccid of the profile.
      * @param portIndex the Port index is the unique index referring to a port.
-     * @param refresh Whether sending the REFRESH command to modem.
-     * @param executor The executor through which the callback should be invoked.
-     * @param callback The callback to get the result code.
+     * @param refresh   Whether sending the REFRESH command to modem.
+     * @param executor  The executor through which the callback should be invoked.
+     * @param callback  The callback to get the result code.
      */
     public void disableProfile(@Nullable String cardId, @Nullable String iccid, int portIndex,
             boolean refresh, @NonNull @CallbackExecutor Executor executor,
@@ -283,14 +321,13 @@
      * Switches from the current profile to another profile. The current profile will be disabled
      * and the specified profile will be enabled.
      *
-     * @param cardId The Id of the eUICC.
-     * @param iccid The iccid of the profile to switch to.
-     * @param refresh Whether sending the REFRESH command to modem.
+     * @param cardId   The Id of the eUICC.
+     * @param iccid    The iccid of the profile to switch to.
+     * @param refresh  Whether sending the REFRESH command to modem.
      * @param executor The executor through which the callback should be invoked.
      * @param callback The callback to get the result code and the EuiccProfileInfo enabled.
-     *
      * @deprecated instead use {@link #switchToProfile(String, String, int, boolean, Executor,
-     *             ResultCallback)}
+     * ResultCallback)}
      */
     @Deprecated
     public void switchToProfile(String cardId, String iccid, boolean refresh,
@@ -320,12 +357,12 @@
      * and the specified profile will be enabled. Here portIndex specifies on which port the
      * profile is to be enabled.
      *
-     * @param cardId The Id of the eUICC.
-     * @param iccid The iccid of the profile to switch to.
+     * @param cardId    The Id of the eUICC.
+     * @param iccid     The iccid of the profile to switch to.
      * @param portIndex The Port index is the unique index referring to a port.
-     * @param refresh Whether sending the REFRESH command to modem.
-     * @param executor The executor through which the callback should be invoked.
-     * @param callback The callback to get the result code and the EuiccProfileInfo enabled.
+     * @param refresh   Whether sending the REFRESH command to modem.
+     * @param executor  The executor through which the callback should be invoked.
+     * @param callback  The callback to get the result code and the EuiccProfileInfo enabled.
      */
     public void switchToProfile(@Nullable String cardId, @Nullable String iccid, int portIndex,
             boolean refresh, @NonNull @CallbackExecutor Executor executor,
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 9ab5aeb..53dff54 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -17,6 +17,7 @@
 package android.telephony.ims;
 
 import android.annotation.LongDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
@@ -44,11 +45,18 @@
 
 import com.android.ims.internal.IImsFeatureStatusCallback;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.function.Supplier;
 
 /**
  * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
@@ -173,7 +181,21 @@
     private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
 
     private IImsServiceControllerListener mListener;
+    private Executor mExecutor;
 
+    /**
+     * Create a new ImsService.
+     * <p>
+     * Method stubs called from the framework will be called asynchronously. Vendor specifies the
+     * {@link Executor} that the methods stubs will be called. If mExecutor is set to null by
+     * vendor use Runnable::run.
+     */
+    public ImsService() {
+        mExecutor = ImsService.this.getExecutor();
+        if (mExecutor == null) {
+            mExecutor = Runnable::run;
+        }
+    }
 
     /**
      * Listener that notifies the framework of ImsService changes.
@@ -201,78 +223,132 @@
 
         @Override
         public IImsMmTelFeature createMmTelFeature(int slotId) {
-            return createMmTelFeatureInternal(slotId);
+            return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId),
+                "createMmTelFeature");
         }
 
         @Override
         public IImsRcsFeature createRcsFeature(int slotId) {
-            return createRcsFeatureInternal(slotId);
+            return executeMethodAsyncForResult(() -> createRcsFeatureInternal(slotId),
+                "createRcsFeature");
         }
 
         @Override
         public void addFeatureStatusCallback(int slotId, int featureType,
                 IImsFeatureStatusCallback c) {
-            ImsService.this.addImsFeatureStatusCallback(slotId, featureType, c);
+            executeMethodAsync(() -> ImsService.this.addImsFeatureStatusCallback(
+                    slotId, featureType, c), "addFeatureStatusCallback");
         }
 
         @Override
         public void removeFeatureStatusCallback(int slotId, int featureType,
                 IImsFeatureStatusCallback c) {
-            ImsService.this.removeImsFeatureStatusCallback(slotId, featureType, c);
+            executeMethodAsync(() -> ImsService.this.removeImsFeatureStatusCallback(
+                    slotId, featureType, c), "removeFeatureStatusCallback");
         }
 
         @Override
         public void removeImsFeature(int slotId, int featureType) {
-            ImsService.this.removeImsFeature(slotId, featureType);
+            executeMethodAsync(() -> ImsService.this.removeImsFeature(slotId, featureType),
+                    "removeImsFeature");
         }
 
         @Override
         public ImsFeatureConfiguration querySupportedImsFeatures() {
-            return ImsService.this.querySupportedImsFeatures();
+            return executeMethodAsyncForResult(() -> ImsService.this.querySupportedImsFeatures(),
+                    "ImsFeatureConfiguration");
         }
 
         @Override
         public long getImsServiceCapabilities() {
-            long caps = ImsService.this.getImsServiceCapabilities();
-            long sanitizedCaps = sanitizeCapabilities(caps);
-            if (caps != sanitizedCaps) {
-                Log.w(LOG_TAG, "removing invalid bits from field: 0x"
-                        + Long.toHexString(caps ^ sanitizedCaps));
-            }
-            return sanitizedCaps;
+            return executeMethodAsyncForResult(() -> {
+                long caps = ImsService.this.getImsServiceCapabilities();
+                long sanitizedCaps = sanitizeCapabilities(caps);
+                if (caps != sanitizedCaps) {
+                    Log.w(LOG_TAG, "removing invalid bits from field: 0x"
+                            + Long.toHexString(caps ^ sanitizedCaps));
+                }
+                return sanitizedCaps;
+            }, "getImsServiceCapabilities");
         }
 
         @Override
         public void notifyImsServiceReadyForFeatureCreation() {
-            ImsService.this.readyForFeatureCreation();
+            executeMethodAsync(() -> ImsService.this.readyForFeatureCreation(),
+                    "notifyImsServiceReadyForFeatureCreation");
         }
 
         @Override
         public IImsConfig getConfig(int slotId) {
-            ImsConfigImplBase c = ImsService.this.getConfig(slotId);
-            return c != null ? c.getIImsConfig() : null;
+            return executeMethodAsyncForResult(() -> {
+                ImsConfigImplBase c = ImsService.this.getConfig(slotId);
+                if (c != null) {
+                    c.setDefaultExecutor(mExecutor);
+                    return c.getIImsConfig();
+                } else {
+                    return null;
+                }
+            }, "getConfig");
         }
 
         @Override
         public IImsRegistration getRegistration(int slotId) {
-            ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
-            return r != null ? r.getBinder() : null;
+            return executeMethodAsyncForResult(() -> {
+                ImsRegistrationImplBase r =  ImsService.this.getRegistration(slotId);
+                if (r != null) {
+                    r.setDefaultExecutor(mExecutor);
+                    return r.getBinder();
+                } else {
+                    return null;
+                }
+            }, "getRegistration");
         }
 
         @Override
         public ISipTransport getSipTransport(int slotId) {
-            SipTransportImplBase s = ImsService.this.getSipTransport(slotId);
-            return s != null ? s.getBinder() : null;
+            return executeMethodAsyncForResult(() -> {
+                SipTransportImplBase s =  ImsService.this.getSipTransport(slotId);
+                if (s != null) {
+                    s.setDefaultExecutor(mExecutor);
+                    return s.getBinder();
+                } else {
+                    return null;
+                }
+            }, "getSipTransport");
         }
 
         @Override
         public void enableIms(int slotId) {
-            ImsService.this.enableIms(slotId);
+            executeMethodAsync(() -> ImsService.this.enableIms(slotId), "enableIms");
         }
 
         @Override
         public void disableIms(int slotId) {
-            ImsService.this.disableIms(slotId);
+            executeMethodAsync(() -> ImsService.this.disableIms(slotId), "disableIms");
+        }
+
+        // Call the methods with a clean calling identity on the executor and wait indefinitely for
+        // the future to return.
+        private void executeMethodAsync(Runnable r, String errorLogName) {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+            }
+        }
+
+        private <T> T executeMethodAsyncForResult(Supplier<T> r, String errorLogName) {
+            CompletableFuture<T> future = CompletableFuture.supplyAsync(
+                    () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+            try {
+                return future.get();
+            } catch (ExecutionException | InterruptedException e) {
+                Log.w(LOG_TAG, "ImsService Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                return null;
+            }
         }
     };
 
@@ -300,6 +376,7 @@
         MmTelFeature f = createMmTelFeature(slotId);
         if (f != null) {
             setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
+            f.setDefaultExecutor(mExecutor);
             return f.getBinder();
         } else {
             Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
@@ -310,6 +387,7 @@
     private IImsRcsFeature createRcsFeatureInternal(int slotId) {
         RcsFeature f = createRcsFeature(slotId);
         if (f != null) {
+            f.setDefaultExecutor(mExecutor);
             setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
             return f.getBinder();
         } else {
@@ -562,4 +640,15 @@
         result.append("}");
         return result.toString();
     }
+
+    /**
+     * The ImsService will now be able to define an Executor that the ImsService can be used to
+     * execute the methods. By default all ImsService level method calls will use this Executor.
+     * The ImsService has set the default executor as Runnable::run,
+     * Should be override or default executor will be used.
+     *  @return an Executor used to execute methods called remotely by the framework.
+     */
+    public @NonNull Executor getExecutor() {
+        return Runnable::run;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 9a3f592..7fdf21b 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -40,16 +40,25 @@
 import android.telephony.ims.stub.ImsSmsImplBase;
 import android.telephony.ims.stub.ImsUtImplBase;
 import android.util.ArraySet;
+import android.util.Log;
 
 import com.android.ims.internal.IImsCallSession;
 import com.android.ims.internal.IImsEcbm;
 import com.android.ims.internal.IImsMultiEndpoint;
 import com.android.ims.internal.IImsUt;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
 
 /**
  * Base implementation for Voice and SMS (IR-92) and Video (IR-94) IMS support.
@@ -60,6 +69,7 @@
 public class MmTelFeature extends ImsFeature {
 
     private static final String LOG_TAG = "MmTelFeature";
+    private Executor mExecutor;
 
     /**
      * @hide
@@ -68,160 +78,261 @@
     public MmTelFeature() {
     }
 
+    /**
+     * Create a new MmTelFeature using the Executor specified for methods being called by the
+     * framework.
+     * @param executor The executor for the framework to use when executing the methods overridden
+     * by the implementation of MmTelFeature.
+     * @hide
+     */
+    @SystemApi
+    public MmTelFeature(@NonNull Executor executor) {
+        super();
+        mExecutor = executor;
+    }
+
     private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() {
 
         @Override
         public void setListener(IImsMmTelListener l) {
-            MmTelFeature.this.setListener(l);
+            executeMethodAsyncNoException(() -> MmTelFeature.this.setListener(l), "setListener");
         }
 
         @Override
         public int getFeatureState() throws RemoteException {
-            try {
-                return MmTelFeature.this.getFeatureState();
-            } catch (Exception e) {
-                throw new RemoteException(e.getMessage());
-            }
+            return executeMethodAsyncForResult(() -> MmTelFeature.this.getFeatureState(),
+                    "getFeatureState");
         }
 
-
         @Override
         public ImsCallProfile createCallProfile(int callSessionType, int callType)
                 throws RemoteException {
-            synchronized (mLock) {
-                try {
-                    return MmTelFeature.this.createCallProfile(callSessionType, callType);
-                } catch (Exception e) {
-                    throw new RemoteException(e.getMessage());
-                }
-            }
+            return executeMethodAsyncForResult(() -> MmTelFeature.this.createCallProfile(
+                    callSessionType, callType), "createCallProfile");
         }
 
         @Override
         public void changeOfferedRtpHeaderExtensionTypes(List<RtpHeaderExtensionType> types)
                 throws RemoteException {
-            synchronized (mLock) {
-                try {
-                    MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(new ArraySet<>(types));
-                } catch (Exception e) {
-                    throw new RemoteException(e.getMessage());
-                }
-            }
+            executeMethodAsync(() -> MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(
+                    new ArraySet<>(types)), "changeOfferedRtpHeaderExtensionTypes");
         }
 
         @Override
         public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException {
-            synchronized (mLock) {
-                return createCallSessionInterface(profile);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            IImsCallSession result = executeMethodAsyncForResult(() -> {
+                try {
+                    return createCallSessionInterface(profile);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                    return null;
+                }
+            }, "createCallSession");
+
+            if (exceptionRef.get() != null) {
+                throw exceptionRef.get();
             }
+
+            return result;
         }
 
         @Override
         public int shouldProcessCall(String[] numbers) {
-            synchronized (mLock) {
-                return MmTelFeature.this.shouldProcessCall(numbers);
+            Integer result = executeMethodAsyncForResultNoException(() ->
+                    MmTelFeature.this.shouldProcessCall(numbers), "shouldProcessCall");
+            if (result != null) {
+                return result.intValue();
+            } else {
+                return PROCESS_CALL_CSFB;
             }
         }
 
         @Override
         public IImsUt getUtInterface() throws RemoteException {
-            synchronized (mLock) {
-                return MmTelFeature.this.getUtInterface();
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            IImsUt result = executeMethodAsyncForResult(() -> {
+                try {
+                    return MmTelFeature.this.getUtInterface();
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                    return null;
+                }
+            }, "getUtInterface");
+
+            if (exceptionRef.get() != null) {
+                throw exceptionRef.get();
             }
+
+            return result;
         }
 
         @Override
         public IImsEcbm getEcbmInterface() throws RemoteException {
-            synchronized (mLock) {
-                return MmTelFeature.this.getEcbmInterface();
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            IImsEcbm result = executeMethodAsyncForResult(() -> {
+                try {
+                    return MmTelFeature.this.getEcbmInterface();
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                    return null;
+                }
+            }, "getEcbmInterface");
+
+            if (exceptionRef.get() != null) {
+                throw exceptionRef.get();
             }
+
+            return result;
         }
 
         @Override
         public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException {
-            synchronized (mLock) {
-                try {
-                    MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage);
-                } catch (Exception e) {
-                    throw new RemoteException(e.getMessage());
-                }
-            }
+            executeMethodAsync(() -> MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage),
+                    "setUiTtyMode");
         }
 
         @Override
         public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
-            synchronized (mLock) {
-                return MmTelFeature.this.getMultiEndpointInterface();
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            IImsMultiEndpoint result = executeMethodAsyncForResult(() -> {
+                try {
+                    return MmTelFeature.this.getMultiEndpointInterface();
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                    return null;
+                }
+            }, "getMultiEndpointInterface");
+
+            if (exceptionRef.get() != null) {
+                throw exceptionRef.get();
             }
+
+            return result;
         }
 
         @Override
         public int queryCapabilityStatus() {
-            return MmTelFeature.this.queryCapabilityStatus().mCapabilities;
+            Integer result = executeMethodAsyncForResultNoException(() -> MmTelFeature.this
+                    .queryCapabilityStatus().mCapabilities, "queryCapabilityStatus");
+
+            if (result != null) {
+                return result.intValue();
+            } else {
+                return 0;
+            }
         }
 
         @Override
         public void addCapabilityCallback(IImsCapabilityCallback c) {
-            // no need to lock, structure already handles multithreading.
-            MmTelFeature.this.addCapabilityCallback(c);
+            executeMethodAsyncNoException(() -> MmTelFeature.this
+                    .addCapabilityCallback(c), "addCapabilityCallback");
         }
 
         @Override
         public void removeCapabilityCallback(IImsCapabilityCallback c) {
-            // no need to lock, structure already handles multithreading.
-            MmTelFeature.this.removeCapabilityCallback(c);
+            executeMethodAsyncNoException(() -> MmTelFeature.this
+                    .removeCapabilityCallback(c), "removeCapabilityCallback");
         }
 
         @Override
         public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
                 IImsCapabilityCallback c) {
-            MmTelFeature.this.requestChangeEnabledCapabilities(request, c);
+            executeMethodAsyncNoException(() -> MmTelFeature.this
+                    .requestChangeEnabledCapabilities(request, c),
+                    "changeCapabilitiesConfiguration");
         }
 
         @Override
         public void queryCapabilityConfiguration(int capability, int radioTech,
                 IImsCapabilityCallback c) {
-            queryCapabilityConfigurationInternal(capability, radioTech, c);
+            executeMethodAsyncNoException(() -> queryCapabilityConfigurationInternal(
+                    capability, radioTech, c), "queryCapabilityConfiguration");
         }
 
         @Override
         public void setSmsListener(IImsSmsListener l) {
-            MmTelFeature.this.setSmsListener(l);
+            executeMethodAsyncNoException(() -> MmTelFeature.this.setSmsListener(l),
+                    "setSmsListener");
         }
 
         @Override
         public void sendSms(int token, int messageRef, String format, String smsc, boolean retry,
                 byte[] pdu) {
-            synchronized (mLock) {
-                MmTelFeature.this.sendSms(token, messageRef, format, smsc, retry, pdu);
-            }
+            executeMethodAsyncNoException(() -> MmTelFeature.this
+                    .sendSms(token, messageRef, format, smsc, retry, pdu), "sendSms");
         }
 
         @Override
         public void acknowledgeSms(int token, int messageRef, int result) {
-            synchronized (mLock) {
-                MmTelFeature.this.acknowledgeSms(token, messageRef, result);
-            }
+            executeMethodAsyncNoException(() -> MmTelFeature.this
+                    .acknowledgeSms(token, messageRef, result), "acknowledgeSms");
         }
 
         @Override
         public void acknowledgeSmsReport(int token, int messageRef, int result) {
-            synchronized (mLock) {
-                MmTelFeature.this.acknowledgeSmsReport(token, messageRef, result);
-            }
+            executeMethodAsyncNoException(() -> MmTelFeature.this
+                    .acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport");
         }
 
         @Override
         public String getSmsFormat() {
-            synchronized (mLock) {
-                return MmTelFeature.this.getSmsFormat();
-            }
+            return executeMethodAsyncForResultNoException(() -> MmTelFeature.this
+                    .getSmsFormat(), "getSmsFormat");
         }
 
         @Override
         public void onSmsReady() {
-            synchronized (mLock) {
-                MmTelFeature.this.onSmsReady();
+            executeMethodAsyncNoException(() -> MmTelFeature.this.onSmsReady(),
+                    "onSmsReady");
+        }
+
+        // Call the methods with a clean calling identity on the executor and wait indefinitely for
+        // the future to return.
+        private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                throw new RemoteException(e.getMessage());
+            }
+        }
+
+        private void executeMethodAsyncNoException(Runnable r, String errorLogName) {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+            }
+        }
+
+        private <T> T executeMethodAsyncForResult(Supplier<T> r,
+                String errorLogName) throws RemoteException {
+            CompletableFuture<T> future = CompletableFuture.supplyAsync(
+                    () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+            try {
+                return future.get();
+            } catch (ExecutionException | InterruptedException e) {
+                Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                throw new RemoteException(e.getMessage());
+            }
+        }
+
+        private <T> T executeMethodAsyncForResultNoException(Supplier<T> r,
+                String errorLogName) {
+            CompletableFuture<T> future = CompletableFuture.supplyAsync(
+                    () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+            try {
+                return future.get();
+            } catch (ExecutionException | InterruptedException e) {
+                Log.w(LOG_TAG, "MmTelFeature Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                return null;
             }
         }
     };
@@ -672,7 +783,12 @@
     public IImsCallSession createCallSessionInterface(ImsCallProfile profile)
             throws RemoteException {
         ImsCallSessionImplBase s = MmTelFeature.this.createCallSession(profile);
-        return s != null ? s.getServiceImpl() : null;
+        if (s != null) {
+            s.setDefaultExecutor(mExecutor);
+            return s.getServiceImpl();
+        } else {
+            return null;
+        }
     }
 
     /**
@@ -713,7 +829,12 @@
      */
     protected IImsUt getUtInterface() throws RemoteException {
         ImsUtImplBase utImpl = getUt();
-        return utImpl != null ? utImpl.getInterface() : null;
+        if (utImpl != null) {
+            utImpl.setDefaultExecutor(mExecutor);
+            return utImpl.getInterface();
+        } else {
+            return null;
+        }
     }
 
     /**
@@ -721,7 +842,12 @@
      */
     protected IImsEcbm getEcbmInterface() throws RemoteException {
         ImsEcbmImplBase ecbmImpl = getEcbm();
-        return ecbmImpl != null ? ecbmImpl.getImsEcbm() : null;
+        if (ecbmImpl != null) {
+            ecbmImpl.setDefaultExecutor(mExecutor);
+            return ecbmImpl.getImsEcbm();
+        } else {
+            return null;
+        }
     }
 
     /**
@@ -729,7 +855,12 @@
      */
     public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
         ImsMultiEndpointImplBase multiendpointImpl = getMultiEndpoint();
-        return multiendpointImpl != null ? multiendpointImpl.getIImsMultiEndpoint() : null;
+        if (multiendpointImpl != null) {
+            multiendpointImpl.setDefaultExecutor(mExecutor);
+            return multiendpointImpl.getIImsMultiEndpoint();
+        } else {
+            return null;
+        }
     }
 
     /**
@@ -859,4 +990,16 @@
     public final IImsMmTelFeature getBinder() {
         return mImsMMTelBinder;
     }
+
+    /**
+     * Set default Executor from ImsService.
+     * @param executor The default executor for the framework to use when executing the methods
+     * overridden by the implementation of MmTelFeature.
+     * @hide
+     */
+    public final void setDefaultExecutor(@NonNull Executor executor) {
+        if (mExecutor == null) {
+            mExecutor = executor;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 18cc37d..11cf0e3 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -70,7 +70,7 @@
         // Reference the outer class in order to have better test coverage metrics instead of
         // creating a inner class referencing the outer class directly.
         private final RcsFeature mReference;
-        private final Executor mExecutor;
+        private Executor mExecutor;
 
         RcsFeatureBinder(RcsFeature classRef, @CallbackExecutor Executor executor) {
             mReference = classRef;
@@ -259,7 +259,7 @@
         }
     }
 
-    private final Executor mExecutor;
+    private Executor mExecutor;
     private final RcsFeatureBinder mImsRcsBinder;
     private RcsCapabilityExchangeImplBase mCapabilityExchangeImpl;
     private CapabilityExchangeEventListener mCapExchangeEventListener;
@@ -270,13 +270,9 @@
      * Method stubs called from the framework will be called asynchronously. To specify the
      * {@link Executor} that the methods stubs will be called, use
      * {@link RcsFeature#RcsFeature(Executor)} instead.
-     *
-     * @deprecated Use {@link #RcsFeature(Executor)} to create the RcsFeature.
      */
-    @Deprecated
     public RcsFeature() {
         super();
-        mExecutor = Runnable::run;
         // Run on the Binder threads that call them.
         mImsRcsBinder = new RcsFeatureBinder(this, mExecutor);
     }
@@ -477,4 +473,17 @@
             return mCapabilityExchangeImpl;
         }
     }
+
+    /**
+     * Set default Executor from ImsService.
+     * @param executor The default executor for the framework to use when executing the methods
+     * overridden by the implementation of RcsFeature.
+     * @hide
+     */
+    public final void setDefaultExecutor(@NonNull Executor executor) {
+        if (mImsRcsBinder.mExecutor == null) {
+            mExecutor = executor;
+            mImsRcsBinder.mExecutor = executor;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index a3a6cb8..e810095 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -30,12 +30,20 @@
 import android.telephony.ims.RtpHeaderExtensionType;
 import android.telephony.ims.aidl.IImsCallSessionListener;
 import android.util.ArraySet;
+import android.util.Log;
 
 import com.android.ims.internal.IImsCallSession;
 import com.android.ims.internal.IImsVideoCallProvider;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.function.Supplier;
 
 /**
  * Base implementation of IImsCallSession, which implements stub versions of the methods available.
@@ -48,6 +56,8 @@
 // DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
 // will break other implementations of ImsCallSession maintained by other ImsServices.
 public class ImsCallSessionImplBase implements AutoCloseable {
+
+    private static final String LOG_TAG = "ImsCallSessionImplBase";
     /**
      * Notify USSD Mode.
      */
@@ -110,185 +120,235 @@
         }
     }
 
+    private Executor mExecutor = Runnable::run;
+
     // Non-final for injection by tests
     private IImsCallSession mServiceImpl = new IImsCallSession.Stub() {
         @Override
         public void close() {
-            ImsCallSessionImplBase.this.close();
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.close(), "close");
         }
 
         @Override
         public String getCallId() {
-            return ImsCallSessionImplBase.this.getCallId();
+            return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallId(),
+                    "getCallId");
         }
 
         @Override
         public ImsCallProfile getCallProfile() {
-            return ImsCallSessionImplBase.this.getCallProfile();
+            return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getCallProfile(),
+                    "getCallProfile");
         }
 
         @Override
         public ImsCallProfile getLocalCallProfile() {
-            return ImsCallSessionImplBase.this.getLocalCallProfile();
+            return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
+                    .getLocalCallProfile(), "getLocalCallProfile");
         }
 
         @Override
         public ImsCallProfile getRemoteCallProfile() {
-            return ImsCallSessionImplBase.this.getRemoteCallProfile();
+            return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
+                    .getRemoteCallProfile(), "getRemoteCallProfile");
         }
 
         @Override
         public String getProperty(String name) {
-            return ImsCallSessionImplBase.this.getProperty(name);
+            return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getProperty(name),
+                    "getProperty");
         }
 
         @Override
         public int getState() {
-            return ImsCallSessionImplBase.this.getState();
+            return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.getState(),
+                    "getState");
         }
 
         @Override
         public boolean isInCall() {
-            return ImsCallSessionImplBase.this.isInCall();
+            return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isInCall(),
+                    "isInCall");
         }
 
         @Override
         public void setListener(IImsCallSessionListener listener) {
-            ImsCallSessionImplBase.this.setListener(new ImsCallSessionListener(listener));
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.setListener(
+                    new ImsCallSessionListener(listener)), "setListener");
         }
 
         @Override
         public void setMute(boolean muted) {
-            ImsCallSessionImplBase.this.setMute(muted);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.setMute(muted), "setMute");
         }
 
         @Override
         public void start(String callee, ImsCallProfile profile) {
-            ImsCallSessionImplBase.this.start(callee, profile);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.start(callee, profile), "start");
         }
 
         @Override
         public void startConference(String[] participants, ImsCallProfile profile) throws
                 RemoteException {
-            ImsCallSessionImplBase.this.startConference(participants, profile);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.startConference(participants,
+                    profile), "startConference");
         }
 
         @Override
         public void accept(int callType, ImsStreamMediaProfile profile) {
-            ImsCallSessionImplBase.this.accept(callType, profile);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.accept(callType, profile),
+                    "accept");
         }
 
         @Override
         public void deflect(String deflectNumber) {
-            ImsCallSessionImplBase.this.deflect(deflectNumber);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.deflect(deflectNumber),
+                    "deflect");
         }
 
         @Override
         public void reject(int reason) {
-            ImsCallSessionImplBase.this.reject(reason);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.reject(reason), "reject");
         }
 
         @Override
         public void transfer(@NonNull String number, boolean isConfirmationRequired) {
-            ImsCallSessionImplBase.this.transfer(number, isConfirmationRequired);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.transfer(number,
+                    isConfirmationRequired), "transfer");
         }
 
         @Override
         public void consultativeTransfer(@NonNull IImsCallSession transferToSession) {
-            ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
-            otherSession.setServiceImpl(transferToSession);
-            ImsCallSessionImplBase.this.transfer(otherSession);
+            executeMethodAsync(() -> {
+                ImsCallSessionImplBase otherSession = new ImsCallSessionImplBase();
+                otherSession.setServiceImpl(transferToSession);
+                ImsCallSessionImplBase.this.transfer(otherSession);
+            }, "consultativeTransfer");
         }
 
         @Override
         public void terminate(int reason) {
-            ImsCallSessionImplBase.this.terminate(reason);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.terminate(reason), "terminate");
         }
 
         @Override
         public void hold(ImsStreamMediaProfile profile) {
-            ImsCallSessionImplBase.this.hold(profile);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.hold(profile), "hold");
         }
 
         @Override
         public void resume(ImsStreamMediaProfile profile) {
-            ImsCallSessionImplBase.this.resume(profile);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.resume(profile), "resume");
         }
 
         @Override
         public void merge() {
-            ImsCallSessionImplBase.this.merge();
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.merge(), "merge");
         }
 
         @Override
         public void update(int callType, ImsStreamMediaProfile profile) {
-            ImsCallSessionImplBase.this.update(callType, profile);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.update(callType, profile),
+                    "update");
         }
 
         @Override
         public void extendToConference(String[] participants) {
-            ImsCallSessionImplBase.this.extendToConference(participants);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.extendToConference(participants),
+                    "extendToConference");
         }
 
         @Override
         public void inviteParticipants(String[] participants) {
-            ImsCallSessionImplBase.this.inviteParticipants(participants);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.inviteParticipants(participants),
+                    "inviteParticipants");
         }
 
         @Override
         public void removeParticipants(String[] participants) {
-            ImsCallSessionImplBase.this.removeParticipants(participants);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.removeParticipants(participants),
+                    "removeParticipants");
         }
 
         @Override
         public void sendDtmf(char c, Message result) {
-            ImsCallSessionImplBase.this.sendDtmf(c, result);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.sendDtmf(c, result), "sendDtmf");
         }
 
         @Override
         public void startDtmf(char c) {
-            ImsCallSessionImplBase.this.startDtmf(c);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.startDtmf(c), "startDtmf");
         }
 
         @Override
         public void stopDtmf() {
-            ImsCallSessionImplBase.this.stopDtmf();
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.stopDtmf(), "stopDtmf");
         }
 
         @Override
         public void sendUssd(String ussdMessage) {
-            ImsCallSessionImplBase.this.sendUssd(ussdMessage);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.sendUssd(ussdMessage), "sendUssd");
         }
 
         @Override
         public IImsVideoCallProvider getVideoCallProvider() {
-            return ImsCallSessionImplBase.this.getVideoCallProvider();
+            return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this
+                    .getVideoCallProvider(), "getVideoCallProvider");
         }
 
         @Override
         public boolean isMultiparty() {
-            return ImsCallSessionImplBase.this.isMultiparty();
+            return executeMethodAsyncForResult(() -> ImsCallSessionImplBase.this.isMultiparty(),
+                    "isMultiparty");
         }
 
         @Override
         public void sendRttModifyRequest(ImsCallProfile toProfile) {
-            ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyRequest(toProfile),
+                    "sendRttModifyRequest");
         }
 
         @Override
         public void sendRttModifyResponse(boolean status) {
-            ImsCallSessionImplBase.this.sendRttModifyResponse(status);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttModifyResponse(status),
+                    "sendRttModifyResponse");
         }
 
         @Override
         public void sendRttMessage(String rttMessage) {
-            ImsCallSessionImplBase.this.sendRttMessage(rttMessage);
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRttMessage(rttMessage),
+                    "sendRttMessage");
         }
 
         @Override
         public void sendRtpHeaderExtensions(@NonNull List<RtpHeaderExtension> extensions) {
-            ImsCallSessionImplBase.this.sendRtpHeaderExtensions(
-                    new ArraySet<RtpHeaderExtension>(extensions));
+            executeMethodAsync(() -> ImsCallSessionImplBase.this.sendRtpHeaderExtensions(
+                    new ArraySet<RtpHeaderExtension>(extensions)), "sendRtpHeaderExtensions");
+        }
+
+        // Call the methods with a clean calling identity on the executor and wait indefinitely for
+        // the future to return.
+        private void executeMethodAsync(Runnable r, String errorLogName) {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+            }
+        }
+
+        private <T> T executeMethodAsyncForResult(Supplier<T> r,
+                String errorLogName) {
+            CompletableFuture<T> future = CompletableFuture.supplyAsync(
+                    () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+            try {
+                return future.get();
+            } catch (ExecutionException | InterruptedException e) {
+                Log.w(LOG_TAG, "ImsCallSessionImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                return null;
+            }
         }
     };
 
@@ -674,4 +734,14 @@
     public void setServiceImpl(IImsCallSession serviceImpl) {
         mServiceImpl = serviceImpl;
     }
+
+    /**
+     * Set default Executor from MmTelFeature.
+     * @param executor The default executor for the framework to use when executing the methods
+     * overridden by the implementation of ImsCallSession.
+     * @hide
+     */
+    public final void setDefaultExecutor(@NonNull Executor executor) {
+        mExecutor = executor;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index d75da90..11fc328 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -33,12 +33,21 @@
 import com.android.ims.ImsConfig;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.util.RemoteCallbackListExt;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
 
 /**
  * Controls the modification of IMS specific configurations. For more information on the supported
@@ -81,21 +90,48 @@
         WeakReference<ImsConfigImplBase> mImsConfigImplBaseWeakReference;
         private HashMap<Integer, Integer> mProvisionedIntValue = new HashMap<>();
         private HashMap<Integer, String> mProvisionedStringValue = new HashMap<>();
+        private final Object mLock = new Object();
+        private Executor mExecutor;
 
         @VisibleForTesting
-        public ImsConfigStub(ImsConfigImplBase imsConfigImplBase) {
+        public ImsConfigStub(ImsConfigImplBase imsConfigImplBase, Executor executor) {
+            mExecutor = executor;
             mImsConfigImplBaseWeakReference =
                     new WeakReference<ImsConfigImplBase>(imsConfigImplBase);
         }
 
         @Override
         public void addImsConfigCallback(IImsConfigCallback c) throws RemoteException {
-            getImsConfigImpl().addImsConfigCallback(c);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    getImsConfigImpl().addImsConfigCallback(c);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "addImsConfigCallback");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception addImsConfigCallback");
+                throw exceptionRef.get();
+            }
         }
 
         @Override
         public void removeImsConfigCallback(IImsConfigCallback c) throws RemoteException {
-            getImsConfigImpl().removeImsConfigCallback(c);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    getImsConfigImpl().removeImsConfigCallback(c);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "removeImsConfigCallback");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception removeImsConfigCallback");
+                throw exceptionRef.get();
+            }
         }
 
         /**
@@ -108,16 +144,34 @@
          * unavailable.
          */
         @Override
-        public synchronized int getConfigInt(int item) throws RemoteException {
-            if (mProvisionedIntValue.containsKey(item)) {
-                return mProvisionedIntValue.get(item);
-            } else {
-                int retVal = getImsConfigImpl().getConfigInt(item);
-                if (retVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
-                    updateCachedValue(item, retVal, false);
+        public int getConfigInt(int item) throws RemoteException {
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            int retVal = executeMethodAsyncForResult(()-> {
+                int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
+                synchronized (mLock) {
+                    if (mProvisionedIntValue.containsKey(item)) {
+                        return mProvisionedIntValue.get(item);
+                    } else {
+                        try {
+                            returnVal = getImsConfigImpl().getConfigInt(item);
+                            if (returnVal != ImsConfig.OperationStatusConstants.UNKNOWN) {
+                                mProvisionedIntValue.put(item, returnVal);
+                            }
+                        } catch (RemoteException e) {
+                            exceptionRef.set(e);
+                            return returnVal;
+                        }
+                    }
                 }
-                return retVal;
+                return returnVal;
+            }, "getConfigInt");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception getConfigString");
+                throw exceptionRef.get();
             }
+
+            return retVal;
         }
 
         /**
@@ -129,16 +183,34 @@
          * @return value in String format.
          */
         @Override
-        public synchronized String getConfigString(int item) throws RemoteException {
-            if (mProvisionedStringValue.containsKey(item)) {
-                return mProvisionedStringValue.get(item);
-            } else {
-                String retVal = getImsConfigImpl().getConfigString(item);
-                if (retVal != null) {
-                    updateCachedValue(item, retVal, false);
+        public String getConfigString(int item) throws RemoteException {
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            String retVal = executeMethodAsyncForResult(()-> {
+                String returnVal = null;
+                synchronized (mLock) {
+                    if (mProvisionedStringValue.containsKey(item)) {
+                        returnVal = mProvisionedStringValue.get(item);
+                    } else {
+                        try {
+                            returnVal = getImsConfigImpl().getConfigString(item);
+                            if (returnVal != null) {
+                                mProvisionedStringValue.put(item, returnVal);
+                            }
+                        } catch (RemoteException e) {
+                            exceptionRef.set(e);
+                            return returnVal;
+                        }
+                    }
                 }
-                return retVal;
+                return returnVal;
+            }, "getConfigString");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception getConfigString");
+                throw exceptionRef.get();
             }
+
+            return retVal;
         }
 
         /**
@@ -153,14 +225,32 @@
          * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
          */
         @Override
-        public synchronized int setConfigInt(int item, int value) throws RemoteException {
-            mProvisionedIntValue.remove(item);
-            int retVal = getImsConfigImpl().setConfig(item, value);
-            if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
-                updateCachedValue(item, value, true);
-            } else {
-                Log.d(TAG, "Set provision value of " + item +
-                        " to " + value + " failed with error code " + retVal);
+        public int setConfigInt(int item, int value) throws RemoteException {
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            int retVal = executeMethodAsyncForResult(()-> {
+                int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
+                try {
+                    synchronized (mLock) {
+                        mProvisionedIntValue.remove(item);
+                        returnVal = getImsConfigImpl().setConfig(item, value);
+                        if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+                            mProvisionedIntValue.put(item, value);
+                        } else {
+                            Log.d(TAG, "Set provision value of " + item
+                                    + " to " + value + " failed with error code " + returnVal);
+                        }
+                    }
+                    notifyImsConfigChanged(item, value);
+                    return returnVal;
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                    return returnVal;
+                }
+            }, "setConfigInt");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception setConfigInt");
+                throw exceptionRef.get();
             }
 
             return retVal;
@@ -178,12 +268,30 @@
          * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}.
          */
         @Override
-        public synchronized int setConfigString(int item, String value)
+        public int setConfigString(int item, String value)
                 throws RemoteException {
-            mProvisionedStringValue.remove(item);
-            int retVal = getImsConfigImpl().setConfig(item, value);
-            if (retVal == ImsConfig.OperationStatusConstants.SUCCESS) {
-                updateCachedValue(item, value, true);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            int retVal = executeMethodAsyncForResult(()-> {
+                int returnVal = ImsConfig.OperationStatusConstants.UNKNOWN;
+                try {
+                    synchronized (mLock) {
+                        mProvisionedStringValue.remove(item);
+                        returnVal = getImsConfigImpl().setConfig(item, value);
+                        if (returnVal == ImsConfig.OperationStatusConstants.SUCCESS) {
+                            mProvisionedStringValue.put(item, value);
+                        }
+                    }
+                    notifyImsConfigChanged(item, value);
+                    return returnVal;
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                    return returnVal;
+                }
+            }, "setConfigString");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception setConfigInt");
+                throw exceptionRef.get();
             }
 
             return retVal;
@@ -191,7 +299,19 @@
 
         @Override
         public void updateImsCarrierConfigs(PersistableBundle bundle) throws RemoteException {
-            getImsConfigImpl().updateImsCarrierConfigs(bundle);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    getImsConfigImpl().updateImsCarrierConfigs(bundle);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "updateImsCarrierConfigs");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception updateImsCarrierConfigs");
+                throw exceptionRef.get();
+            }
         }
 
         private ImsConfigImplBase getImsConfigImpl() throws RemoteException {
@@ -206,13 +326,37 @@
         @Override
         public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed)
                 throws RemoteException {
-            getImsConfigImpl().onNotifyRcsAutoConfigurationReceived(config, isCompressed);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    getImsConfigImpl().onNotifyRcsAutoConfigurationReceived(config, isCompressed);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "notifyRcsAutoConfigurationReceived");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception notifyRcsAutoConfigurationReceived");
+                throw exceptionRef.get();
+            }
         }
 
         @Override
         public void notifyRcsAutoConfigurationRemoved()
                 throws RemoteException {
-            getImsConfigImpl().onNotifyRcsAutoConfigurationRemoved();
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    getImsConfigImpl().onNotifyRcsAutoConfigurationRemoved();
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "notifyRcsAutoConfigurationRemoved");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception notifyRcsAutoConfigurationRemoved");
+                throw exceptionRef.get();
+            }
         }
 
         private void notifyImsConfigChanged(int item, int value) throws RemoteException {
@@ -223,50 +367,144 @@
             getImsConfigImpl().notifyConfigChanged(item, value);
         }
 
-        protected synchronized void updateCachedValue(int item, int value, boolean notifyChange)
-        throws RemoteException {
-            mProvisionedIntValue.put(item, value);
-            if (notifyChange) {
-                notifyImsConfigChanged(item, value);
+        protected void updateCachedValue(int item, int value) {
+            synchronized (mLock) {
+                mProvisionedIntValue.put(item, value);
             }
         }
 
-        protected synchronized void updateCachedValue(int item, String value,
-                boolean notifyChange) throws RemoteException {
-            mProvisionedStringValue.put(item, value);
-            if (notifyChange) {
-                notifyImsConfigChanged(item, value);
+        protected void updateCachedValue(int item, String value) {
+            synchronized (mLock) {
+                mProvisionedStringValue.put(item, value);
             }
         }
 
         @Override
         public void addRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
-            getImsConfigImpl().addRcsConfigCallback(c);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    getImsConfigImpl().addRcsConfigCallback(c);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "addRcsConfigCallback");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception addRcsConfigCallback");
+                throw exceptionRef.get();
+            }
         }
 
         @Override
         public void removeRcsConfigCallback(IRcsConfigCallback c) throws RemoteException {
-            getImsConfigImpl().removeRcsConfigCallback(c);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    getImsConfigImpl().removeRcsConfigCallback(c);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "removeRcsConfigCallback");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception removeRcsConfigCallback");
+                throw exceptionRef.get();
+            }
         }
 
         @Override
         public void triggerRcsReconfiguration() throws RemoteException {
-            getImsConfigImpl().triggerAutoConfiguration();
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    getImsConfigImpl().triggerAutoConfiguration();
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "triggerRcsReconfiguration");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception triggerRcsReconfiguration");
+                throw exceptionRef.get();
+            }
         }
 
         @Override
         public void setRcsClientConfiguration(RcsClientConfiguration rcc) throws RemoteException {
-            getImsConfigImpl().setRcsClientConfiguration(rcc);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    getImsConfigImpl().setRcsClientConfiguration(rcc);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "setRcsClientConfiguration");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception setRcsClientConfiguration");
+                throw exceptionRef.get();
+            }
         }
 
         @Override
         public void notifyIntImsConfigChanged(int item, int value) throws RemoteException {
-            notifyImsConfigChanged(item, value);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    notifyImsConfigChanged(item, value);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "notifyIntImsConfigChanged");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception notifyIntImsConfigChanged");
+                throw exceptionRef.get();
+            }
         }
 
         @Override
         public void notifyStringImsConfigChanged(int item, String value) throws RemoteException {
-            notifyImsConfigChanged(item, value);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(()-> {
+                try {
+                    notifyImsConfigChanged(item, value);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "notifyStringImsConfigChanged");
+
+            if (exceptionRef.get() != null) {
+                Log.d(TAG, "ImsConfigImplBase Exception notifyStringImsConfigChanged");
+                throw exceptionRef.get();
+            }
+        }
+
+        // Call the methods with a clean calling identity on the executor and wait indefinitely for
+        // the future to return.
+        private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(TAG, "ImsConfigImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                throw new RemoteException(e.getMessage());
+            }
+        }
+
+        private <T> T executeMethodAsyncForResult(Supplier<T> r,
+                String errorLogName) throws RemoteException {
+            CompletableFuture<T> future = CompletableFuture.supplyAsync(
+                    () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+            try {
+                return future.get();
+            } catch (ExecutionException | InterruptedException e) {
+                Log.w(TAG, "ImsConfigImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                throw new RemoteException(e.getMessage());
+            }
         }
     }
 
@@ -303,15 +541,24 @@
     ImsConfigStub mImsConfigStub;
 
     /**
-     * Used for compatibility between older versions of the ImsService.
+     * Create a ImsConfig using the Executor specified for methods being called by the
+     * framework.
+     * @param executor The executor for the framework to use when executing the methods overridden
+     * by the implementation of ImsConfig.
+     */
+    public ImsConfigImplBase(@NonNull Executor executor) {
+        mImsConfigStub = new ImsConfigStub(this, executor);
+    }
+
+    /**
      * @hide
      */
-    public ImsConfigImplBase(Context context) {
-        mImsConfigStub = new ImsConfigStub(this);
+    public ImsConfigImplBase(@NonNull Context context) {
+        mImsConfigStub = new ImsConfigStub(this, null);
     }
 
     public ImsConfigImplBase() {
-        mImsConfigStub = new ImsConfigStub(this);
+        mImsConfigStub = new ImsConfigStub(this, null);
     }
 
     /**
@@ -427,8 +674,10 @@
      * @param value in Integer format.
      */
     public final void notifyProvisionedValueChanged(int item, int value) {
+        mImsConfigStub.updateCachedValue(item, value);
+
         try {
-            mImsConfigStub.updateCachedValue(item, value, true);
+            mImsConfigStub.notifyImsConfigChanged(item, value);
         } catch (RemoteException e) {
             Log.w(TAG, "notifyProvisionedValueChanged(int): Framework connection is dead.");
         }
@@ -443,8 +692,10 @@
      * @param value in String format.
      */
     public final void notifyProvisionedValueChanged(int item, String value) {
+        mImsConfigStub.updateCachedValue(item, value);
+
         try {
-        mImsConfigStub.updateCachedValue(item, value, true);
+            mImsConfigStub.notifyImsConfigChanged(item, value);
         } catch (RemoteException e) {
             Log.w(TAG, "notifyProvisionedValueChanged(string): Framework connection is dead.");
         }
@@ -582,4 +833,16 @@
             }
         });
     }
+
+    /**
+     * Set default Executor from ImsService.
+     * @param executor The default executor for the framework to use when executing the methods
+     * overridden by the implementation of ImsConfig.
+     * @hide
+     */
+    public final void setDefaultExecutor(@NonNull Executor executor) {
+        if (mImsConfigStub.mExecutor == null) {
+            mImsConfigStub.mExecutor = executor;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
index 8ad40ed..84b2253 100644
--- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -16,14 +16,21 @@
 
 package android.telephony.ims.stub;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.RemoteException;
 import android.util.Log;
 
 import com.android.ims.internal.IImsEcbm;
 import com.android.ims.internal.IImsEcbmListener;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.util.Objects;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.Executor;
+
 
 /**
  * Base implementation of ImsEcbm, which implements stub versions of the methods
@@ -40,10 +47,12 @@
 
     private final Object mLock = new Object();
     private IImsEcbmListener mListener;
+    private Executor mExecutor = Runnable::run;
+
     private final IImsEcbm mImsEcbm = new IImsEcbm.Stub() {
         @Override
         public void setListener(IImsEcbmListener listener) {
-            synchronized (mLock) {
+            executeMethodAsync(() -> {
                 if (mListener != null && !mListener.asBinder().isBinderAlive()) {
                     Log.w(TAG, "setListener: discarding dead Binder");
                     mListener = null;
@@ -62,12 +71,25 @@
                             + "listener");
                     mListener = listener;
                 }
-            }
+            }, "setListener");
         }
 
         @Override
         public void exitEmergencyCallbackMode() {
-            ImsEcbmImplBase.this.exitEmergencyCallbackMode();
+            executeMethodAsync(() -> ImsEcbmImplBase.this.exitEmergencyCallbackMode(),
+                    "exitEmergencyCallbackMode");
+        }
+
+        // Call the methods with a clean calling identity on the executor and wait indefinitely for
+        // the future to return.
+        private void executeMethodAsync(Runnable r, String errorLogName) {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(TAG, "ImsEcbmImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+            }
         }
     };
 
@@ -123,4 +145,14 @@
             }
         }
     }
+
+    /**
+     * Set default Executor from MmTelFeature.
+     * @param executor The default executor for the framework to use when executing the methods
+     * overridden by the implementation of ImsEcbm.
+     * @hide
+     */
+    public final void setDefaultExecutor(@NonNull Executor executor) {
+        mExecutor = executor;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
index ec1c7b3..a723cd8 100644
--- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -16,6 +16,7 @@
 
 package android.telephony.ims.stub;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.RemoteException;
 import android.telephony.ims.ImsExternalCallState;
@@ -23,9 +24,14 @@
 
 import com.android.ims.internal.IImsExternalCallStateListener;
 import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.Executor;
 
 /**
  * Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
@@ -43,11 +49,13 @@
 
     private IImsExternalCallStateListener mListener;
     private final Object mLock = new Object();
+    private Executor mExecutor = Runnable::run;
+
     private final IImsMultiEndpoint mImsMultiEndpoint = new IImsMultiEndpoint.Stub() {
 
         @Override
         public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
-            synchronized (mLock) {
+            executeMethodAsync(() -> {
                 if (mListener != null && !mListener.asBinder().isBinderAlive()) {
                     Log.w(TAG, "setListener: discarding dead Binder");
                     mListener = null;
@@ -67,12 +75,25 @@
                             + "listener");
                     mListener = listener;
                 }
-            }
+            }, "setListener");
         }
 
         @Override
         public void requestImsExternalCallStateInfo() throws RemoteException {
-            ImsMultiEndpointImplBase.this.requestImsExternalCallStateInfo();
+            executeMethodAsync(() -> ImsMultiEndpointImplBase.this
+                    .requestImsExternalCallStateInfo(), "requestImsExternalCallStateInfo");
+        }
+
+        // Call the methods with a clean calling identity on the executor and wait indefinitely for
+        // the future to return.
+        private void executeMethodAsync(Runnable r, String errorLogName) {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(TAG, "ImsMultiEndpointImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+            }
         }
     };
 
@@ -108,4 +129,14 @@
     public void requestImsExternalCallStateInfo() {
         Log.d(TAG, "requestImsExternalCallStateInfo() not implemented");
     }
+
+    /**
+     * Set default Executor from MmTelFeature.
+     * @param executor The default executor for the framework to use when executing the methods
+     * overridden by the implementation of ImsMultiEndpoint.
+     * @hide
+     */
+    public final void setDefaultExecutor(@NonNull Executor executor) {
+        mExecutor = executor;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 02bcdec..3b151a4 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -31,10 +31,19 @@
 import android.util.Log;
 
 import com.android.internal.telephony.util.RemoteCallbackListExt;
+import com.android.internal.telephony.util.TelephonyUtils;
 import com.android.internal.util.ArrayUtils;
 
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
 
 /**
  * Controls IMS registration for this ImsService and notifies the framework when the IMS
@@ -92,39 +101,114 @@
     // yet.
     private static final int REGISTRATION_STATE_UNKNOWN = -1;
 
+    private Executor mExecutor;
+
+    /**
+     * Create a new ImsRegistration.
+     * <p>
+     * Method stubs called from the framework will be called asynchronously. To specify the
+     * {@link Executor} that the methods stubs will be called, use
+     * {@link ImsRegistrationImplBase#ImsRegistrationImplBase(Executor)} instead.
+     */
+    public ImsRegistrationImplBase() {
+        super();
+    }
+
+    /**
+     * Create a ImsRegistration using the Executor specified for methods being called by the
+     * framework.
+     * @param executor The executor for the framework to use when executing the methods overridden
+     * by the implementation of ImsRegistration.
+     */
+    public ImsRegistrationImplBase(@NonNull Executor executor) {
+        super();
+        mExecutor = executor;
+    }
+
     private final IImsRegistration mBinder = new IImsRegistration.Stub() {
 
         @Override
         public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException {
-            synchronized (mLock) {
-                return (mRegistrationAttributes == null) ? REGISTRATION_TECH_NONE
-                        : mRegistrationAttributes.getRegistrationTechnology();
-            }
+            return executeMethodAsyncForResult(() -> (mRegistrationAttributes == null)
+                    ? REGISTRATION_TECH_NONE : mRegistrationAttributes.getRegistrationTechnology(),
+                    "getRegistrationTechnology");
         }
 
         @Override
         public void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
-            ImsRegistrationImplBase.this.addRegistrationCallback(c);
+            AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+            executeMethodAsync(() -> {
+                try {
+                    ImsRegistrationImplBase.this.addRegistrationCallback(c);
+                } catch (RemoteException e) {
+                    exceptionRef.set(e);
+                }
+            }, "addRegistrationCallback");
+
+            if (exceptionRef.get() != null) {
+                throw exceptionRef.get();
+            }
         }
 
         @Override
         public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
-            ImsRegistrationImplBase.this.removeRegistrationCallback(c);
+            executeMethodAsync(() -> ImsRegistrationImplBase.this.removeRegistrationCallback(c),
+                    "removeRegistrationCallback");
         }
 
         @Override
         public void triggerFullNetworkRegistration(int sipCode, String sipReason) {
-            ImsRegistrationImplBase.this.triggerFullNetworkRegistration(sipCode, sipReason);
+            executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
+                    .triggerFullNetworkRegistration(sipCode, sipReason),
+                    "triggerFullNetworkRegistration");
         }
 
         @Override
         public void triggerUpdateSipDelegateRegistration() {
-            ImsRegistrationImplBase.this.updateSipDelegateRegistration();
+            executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
+                    .updateSipDelegateRegistration(), "triggerUpdateSipDelegateRegistration");
         }
 
         @Override
         public void triggerSipDelegateDeregistration() {
-            ImsRegistrationImplBase.this.triggerSipDelegateDeregistration();
+            executeMethodAsyncNoException(() -> ImsRegistrationImplBase.this
+                    .triggerSipDelegateDeregistration(), "triggerSipDelegateDeregistration");
+        }
+
+        // Call the methods with a clean calling identity on the executor and wait indefinitely for
+        // the future to return.
+        private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                throw new RemoteException(e.getMessage());
+            }
+        }
+
+        private void executeMethodAsyncNoException(Runnable r, String errorLogName) {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+            }
+        }
+
+        private <T> T executeMethodAsyncForResult(Supplier<T> r,
+                String errorLogName) throws RemoteException {
+            CompletableFuture<T> future = CompletableFuture.supplyAsync(
+                    () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+            try {
+                return future.get();
+            } catch (ExecutionException | InterruptedException e) {
+                Log.w(LOG_TAG, "ImsRegistrationImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                throw new RemoteException(e.getMessage());
+            }
         }
     };
 
@@ -394,4 +478,16 @@
             onSubscriberAssociatedUriChanged(c, uris);
         }
     }
+
+    /**
+     * Set default Executor from ImsService.
+     * @param executor The default executor for the framework to use when executing the methods
+     * overridden by the implementation of Registration.
+     * @hide
+     */
+    public final void setDefaultExecutor(@NonNull Executor executor) {
+        if (mExecutor == null) {
+            mExecutor = executor;
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index eb3e8ed..11cdeed 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -27,10 +27,17 @@
 
 import com.android.ims.internal.IImsUt;
 import com.android.ims.internal.IImsUtListener;
+import com.android.internal.telephony.util.TelephonyUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.function.Supplier;
 
 /**
  * Base implementation of IMS UT interface, which implements stubs. Override these methods to
@@ -119,96 +126,108 @@
      */
     public static final int INVALID_RESULT = -1;
 
+    private Executor mExecutor = Runnable::run;
+
     private final IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
         private final Object mLock = new Object();
         private ImsUtListener mUtListener;
 
         @Override
         public void close() throws RemoteException {
-            ImsUtImplBase.this.close();
+            executeMethodAsync(() ->ImsUtImplBase.this.close(), "close");
         }
 
         @Override
         public int queryCallBarring(int cbType) throws RemoteException {
-            return ImsUtImplBase.this.queryCallBarring(cbType);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallBarring(cbType),
+                    "queryCallBarring");
         }
 
         @Override
         public int queryCallForward(int condition, String number) throws RemoteException {
-            return ImsUtImplBase.this.queryCallForward(condition, number);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallForward(
+                    condition, number), "queryCallForward");
         }
 
         @Override
         public int queryCallWaiting() throws RemoteException {
-            return ImsUtImplBase.this.queryCallWaiting();
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCallWaiting(),
+                    "queryCallWaiting");
         }
 
         @Override
         public int queryCLIR() throws RemoteException {
-            return ImsUtImplBase.this.queryCLIR();
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIR(), "queryCLIR");
         }
 
         @Override
         public int queryCLIP() throws RemoteException {
-            return ImsUtImplBase.this.queryCLIP();
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCLIP(), "queryCLIP");
         }
 
         @Override
         public int queryCOLR() throws RemoteException {
-            return ImsUtImplBase.this.queryCOLR();
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLR(), "queryCOLR");
         }
 
         @Override
         public int queryCOLP() throws RemoteException {
-            return ImsUtImplBase.this.queryCOLP();
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.queryCOLP(), "queryCOLP");
         }
 
         @Override
         public int transact(Bundle ssInfo) throws RemoteException {
-            return ImsUtImplBase.this.transact(ssInfo);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.transact(ssInfo),
+                    "transact");
         }
 
         @Override
         public int updateCallBarring(int cbType, int action, String[] barrList) throws
                 RemoteException {
-            return ImsUtImplBase.this.updateCallBarring(cbType, action, barrList);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallBarring(
+                    cbType, action, barrList), "updateCallBarring");
         }
 
         @Override
         public int updateCallForward(int action, int condition, String number, int serviceClass,
                 int timeSeconds) throws RemoteException {
-            return ImsUtImplBase.this.updateCallForward(action, condition, number, serviceClass,
-                    timeSeconds);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallForward(
+                    action, condition, number, serviceClass, timeSeconds), "updateCallForward");
         }
 
         @Override
         public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException {
-            return ImsUtImplBase.this.updateCallWaiting(enable, serviceClass);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCallWaiting(
+                    enable, serviceClass), "updateCallWaiting");
         }
 
         @Override
         public int updateCLIR(int clirMode) throws RemoteException {
-            return ImsUtImplBase.this.updateCLIR(clirMode);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIR(clirMode),
+                    "updateCLIR");
         }
 
         @Override
         public int updateCLIP(boolean enable) throws RemoteException {
-            return ImsUtImplBase.this.updateCLIP(enable);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCLIP(enable),
+                    "updateCLIP");
         }
 
         @Override
         public int updateCOLR(int presentation) throws RemoteException {
-            return ImsUtImplBase.this.updateCOLR(presentation);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLR(presentation),
+                    "updateCOLR");
         }
 
         @Override
         public int updateCOLP(boolean enable) throws RemoteException {
-            return ImsUtImplBase.this.updateCOLP(enable);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this.updateCOLP(enable),
+                    "updateCOLP");
         }
 
         @Override
         public void setListener(IImsUtListener listener) throws RemoteException {
-            synchronized (mLock) {
+            executeMethodAsync(() -> {
                 if (mUtListener != null
                         && !mUtListener.getListenerInterface().asBinder().isBinderAlive()) {
                     Log.w(TAG, "setListener: discarding dead Binder");
@@ -229,29 +248,59 @@
                             + "listener");
                     mUtListener = new ImsUtListener(listener);
                 }
-            }
 
-            ImsUtImplBase.this.setListener(mUtListener);
+                ImsUtImplBase.this.setListener(mUtListener);
+            }, "setListener");
         }
 
         @Override
         public int queryCallBarringForServiceClass(int cbType, int serviceClass)
                 throws RemoteException {
-            return ImsUtImplBase.this.queryCallBarringForServiceClass(cbType, serviceClass);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this
+                    .queryCallBarringForServiceClass(cbType, serviceClass),
+                    "queryCallBarringForServiceClass");
         }
 
         @Override
         public int updateCallBarringForServiceClass(int cbType, int action,
                 String[] barrList, int serviceClass) throws RemoteException {
-            return ImsUtImplBase.this.updateCallBarringForServiceClass(
-                    cbType, action, barrList, serviceClass);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this
+                    .updateCallBarringForServiceClass(cbType, action, barrList, serviceClass),
+                    "updateCallBarringForServiceClass");
         }
 
         @Override
         public int updateCallBarringWithPassword(int cbType, int action, String[] barrList,
                 int serviceClass, String password) throws RemoteException {
-            return ImsUtImplBase.this.updateCallBarringWithPassword(
-                    cbType, action, barrList, serviceClass, password);
+            return executeMethodAsyncForResult(() -> ImsUtImplBase.this
+                    .updateCallBarringWithPassword(cbType, action, barrList, serviceClass,
+                    password), "updateCallBarringWithPassword");
+        }
+
+        // Call the methods with a clean calling identity on the executor and wait indefinitely for
+        // the future to return.
+        private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
+            try {
+                CompletableFuture.runAsync(
+                        () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
+            } catch (CancellationException | CompletionException e) {
+                Log.w(TAG, "ImsUtImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                throw new RemoteException(e.getMessage());
+            }
+        }
+
+        private <T> T executeMethodAsyncForResult(Supplier<T> r,
+                String errorLogName) throws RemoteException {
+            CompletableFuture<T> future = CompletableFuture.supplyAsync(
+                    () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
+            try {
+                return future.get();
+            } catch (ExecutionException | InterruptedException e) {
+                Log.w(TAG, "ImsUtImplBase Binder - " + errorLogName + " exception: "
+                        + e.getMessage());
+                throw new RemoteException(e.getMessage());
+            }
         }
     };
 
@@ -470,4 +519,14 @@
     public IImsUt getInterface() {
         return mServiceImpl;
     }
+
+    /**
+     * Set default Executor from MmTelFeature.
+     * @param executor The default executor for the framework to use when executing the methods
+     * overridden by the implementation of ImsUT.
+     * @hide
+     */
+    public final void setDefaultExecutor(@NonNull Executor executor) {
+        mExecutor = executor;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
index 13ea9973..52538cb 100644
--- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
@@ -86,10 +86,21 @@
         }
     };
 
-    private final Executor mBinderExecutor;
+    private Executor mBinderExecutor;
     private final ArrayList<SipDelegateAidlWrapper> mDelegates = new ArrayList<>();
 
     /**
+     * Create a new SipTransport.
+     * <p>
+     * Method stubs called from the framework will be called asynchronously. To specify the
+     * {@link Executor} that the methods stubs will be called, use
+     * {@link SipTransportImplBase#SipTransportImplBase(Executor)} instead.
+     */
+    public SipTransportImplBase() {
+        super();
+    }
+
+    /**
      * Create an implementation of SipTransportImplBase.
      *
      * @param executor The executor that remote calls from the framework will be called on. This
@@ -212,4 +223,16 @@
     public ISipTransport getBinder() {
         return mSipTransportImpl;
     }
+
+    /**
+     * Set default Executor from ImsService.
+     * @param executor The default executor for the framework to use when executing the methods
+     * overridden by the implementation of SipTransport.
+     * @hide
+     */
+    public final void setDefaultExecutor(@NonNull Executor executor) {
+        if (mBinderExecutor == null) {
+            mBinderExecutor = executor;
+        }
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index f317c92..be54cec 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2513,4 +2513,14 @@
 
     /** Check if telephony new data stack is enabled. */
     boolean isUsingNewDataStack();
+
+    /**
+     *  @return true if the modem service is set successfully, false otherwise.
+     */
+    boolean setModemService(in String serviceName);
+
+    /**
+     * @return the service name of the modem service which bind to.
+     */
+    String getModemService();
 }
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
index c717c09..1734c98 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl
@@ -45,6 +45,8 @@
         in IGetAllProfilesCallback callback);
     oneway void getProfile(String callingPackage, String cardId, String iccid,
         in IGetProfileCallback callback);
+    oneway void getEnabledProfile(String callingPackage, String cardId, int portIndex,
+        in IGetProfileCallback callback);
     oneway void disableProfile(String callingPackage, String cardId, String iccid, int portIndex,
             boolean refresh, in IDisableProfileCallback callback);
     oneway void switchToProfile(String callingPackage, String cardId, String iccid, int portIndex,