Merge "Define margins for complication overlay."
diff --git a/Android.bp b/Android.bp
index 25238e8..7d02d7d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -155,32 +155,9 @@
     name: "framework-all",
     installable: false,
     static_libs: [
-        "android.net.ipsec.ike.impl",
+        "all-framework-module-impl",
         "framework-minus-apex",
-        "framework-appsearch.impl",
-        "framework-connectivity.impl",
-        "framework-connectivity-tiramisu.impl",
-        "framework-graphics.impl",
-        "framework-mediaprovider.impl",
-        "framework-permission.impl",
-        "framework-permission-s.impl",
-        "framework-scheduling.impl",
-        "framework-sdkextensions.impl",
-        "framework-statsd.impl",
-        "framework-supplementalprocess.impl",
-        "framework-tethering.impl",
-        "framework-uwb.impl",
-        "framework-wifi.impl",
-        "updatable-media",
     ],
-    soong_config_variables: {
-        include_nonpublic_framework_api: {
-            static_libs: [
-                "framework-auxiliary.impl",
-                "framework-supplementalapi.impl",
-            ],
-        },
-    },
     apex_available: ["//apex_available:platform"],
     sdk_version: "core_platform",
     visibility: [
@@ -418,7 +395,6 @@
     static_libs: [
         "app-compat-annotations",
         "framework-minus-apex",
-        "framework-appsearch.impl", // TODO(b/146218515): should be removed
         "framework-updatable-stubs-module_libs_api",
     ],
     sdk_version: "core_platform",
@@ -447,7 +423,6 @@
         // TODO: remove these annotations as soon as we can use andoid.support.annotations.*
         ":framework-annotations",
         ":modules-utils-preconditions-srcs",
-        "core/java/android/net/DhcpResults.java",
         "core/java/android/util/IndentingPrintWriter.java",
         "core/java/android/util/LocalLog.java",
         "core/java/com/android/internal/util/HexDump.java",
@@ -607,6 +582,7 @@
     libs: [
         "art.module.public.api",
         "sdk_module-lib_current_framework-tethering",
+        "sdk_module-lib_current_framework-connectivity-tiramisu",
         "sdk_public_current_framework-bluetooth",
         // There are a few classes from modules used by the core that
         // need to be resolved by metalava. We use a prebuilt stub of the
diff --git a/StubLibraries.bp b/StubLibraries.bp
index a0a426e..92e7dc9 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -258,6 +258,7 @@
     srcs: [":module-lib-api-stubs-docs-non-updatable"],
     libs: [
         "sdk_module-lib_current_framework-tethering",
+        "sdk_module-lib_current_framework-connectivity-tiramisu",
         "sdk_public_current_framework-bluetooth",
         // NOTE: The below can be removed once the prebuilt stub contains bluetooth.
         "sdk_system_current_android",
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index b4edd39..2c2af28 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -66,8 +66,8 @@
     },
     visibility: [
         "//frameworks/av/apex:__subpackages__",
-        "//frameworks/base", // For framework-all
         "//frameworks/base/apex/media/service",
+        "//frameworks/base/api", // For framework-all
     ],
 }
 
diff --git a/api/api.go b/api/api.go
index 17649e8..5e5f60e 100644
--- a/api/api.go
+++ b/api/api.go
@@ -27,6 +27,7 @@
 const art = "art.module.public.api"
 const conscrypt = "conscrypt.module.public.api"
 const i18n = "i18n.module.public.api"
+var core_libraries_modules = []string{art, conscrypt, i18n}
 
 // The intention behind this soong plugin is to generate a number of "merged"
 // API-related modules that would otherwise require a large amount of very
@@ -199,9 +200,28 @@
 	ctx.CreateModule(java.LibraryFactory, &props)
 }
 
-func createMergedModuleLibStubs(ctx android.LoadHookContext, modules []string) {
+func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) {
+	// This module is for the "framework-all" module, which should not include the core libraries.
+	modules = removeAll(modules, core_libraries_modules)
+	// TODO(b/214988855): remove the line below when framework-bluetooth has an impl jar.
+	modules = remove(modules, "framework-bluetooth")
+	props := libraryProps{}
+	props.Name = proptools.StringPtr("all-framework-module-impl")
+	props.Static_libs = transformArray(modules, "", ".impl")
+	// Media module's impl jar is called "updatable-media"
+	for i, v := range props.Static_libs {
+		if v == "framework-media.impl" {
+			props.Static_libs[i] = "updatable-media"
+		}
+	}
+	props.Sdk_version = proptools.StringPtr("module_current")
+	props.Visibility = []string{"//frameworks/base"}
+	ctx.CreateModule(java.LibraryFactory, &props)
+}
+
+func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules []string) {
 	// The user of this module compiles against the "core" SDK, so remove core libraries to avoid dupes.
-	modules = removeAll(modules, []string{art, conscrypt, i18n})
+	modules = removeAll(modules, core_libraries_modules)
 	props := libraryProps{}
 	props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api")
 	props.Static_libs = transformArray(modules, "", ".stubs.module_lib")
@@ -269,7 +289,8 @@
 
 	createMergedPublicStubs(ctx, bootclasspath)
 	createMergedSystemStubs(ctx, bootclasspath)
-	createMergedModuleLibStubs(ctx, bootclasspath)
+	createMergedFrameworkModuleLibStubs(ctx, bootclasspath)
+	createMergedFrameworkImpl(ctx, bootclasspath)
 
 	createMergedAnnotations(ctx, bootclasspath)
 
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index 9153426..e346ebf 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -9315,78 +9315,6 @@
 Landroid/app/usage/IUsageStatsManager;->setAppStandbyBuckets(Landroid/content/pm/ParceledListSlice;I)V
 Landroid/app/usage/IUsageStatsManager;->unregisterAppUsageObserver(ILjava/lang/String;)V
 Landroid/app/usage/IUsageStatsManager;->whitelistAppTemporarily(Ljava/lang/String;JI)V
-Landroid/app/usage/NetworkStats$Bucket;->convertDefaultNetworkStatus(I)I
-Landroid/app/usage/NetworkStats$Bucket;->convertMetered(I)I
-Landroid/app/usage/NetworkStats$Bucket;->convertRoaming(I)I
-Landroid/app/usage/NetworkStats$Bucket;->convertSet(I)I
-Landroid/app/usage/NetworkStats$Bucket;->convertState(I)I
-Landroid/app/usage/NetworkStats$Bucket;->convertTag(I)I
-Landroid/app/usage/NetworkStats$Bucket;->convertUid(I)I
-Landroid/app/usage/NetworkStats$Bucket;->mBeginTimeStamp:J
-Landroid/app/usage/NetworkStats$Bucket;->mDefaultNetworkStatus:I
-Landroid/app/usage/NetworkStats$Bucket;->mEndTimeStamp:J
-Landroid/app/usage/NetworkStats$Bucket;->mMetered:I
-Landroid/app/usage/NetworkStats$Bucket;->mRoaming:I
-Landroid/app/usage/NetworkStats$Bucket;->mRxBytes:J
-Landroid/app/usage/NetworkStats$Bucket;->mRxPackets:J
-Landroid/app/usage/NetworkStats$Bucket;->mState:I
-Landroid/app/usage/NetworkStats$Bucket;->mTag:I
-Landroid/app/usage/NetworkStats$Bucket;->mTxBytes:J
-Landroid/app/usage/NetworkStats$Bucket;->mTxPackets:J
-Landroid/app/usage/NetworkStats$Bucket;->mUid:I
-Landroid/app/usage/NetworkStats;-><init>(Landroid/content/Context;Landroid/net/NetworkTemplate;IJJLandroid/net/INetworkStatsService;)V
-Landroid/app/usage/NetworkStats;->fillBucketFromSummaryEntry(Landroid/app/usage/NetworkStats$Bucket;)V
-Landroid/app/usage/NetworkStats;->getDeviceSummaryForNetwork()Landroid/app/usage/NetworkStats$Bucket;
-Landroid/app/usage/NetworkStats;->getNextHistoryBucket(Landroid/app/usage/NetworkStats$Bucket;)Z
-Landroid/app/usage/NetworkStats;->getNextSummaryBucket(Landroid/app/usage/NetworkStats$Bucket;)Z
-Landroid/app/usage/NetworkStats;->getSummaryAggregate()Landroid/app/usage/NetworkStats$Bucket;
-Landroid/app/usage/NetworkStats;->getUid()I
-Landroid/app/usage/NetworkStats;->hasNextUid()Z
-Landroid/app/usage/NetworkStats;->isUidEnumeration()Z
-Landroid/app/usage/NetworkStats;->mCloseGuard:Ldalvik/system/CloseGuard;
-Landroid/app/usage/NetworkStats;->mEndTimeStamp:J
-Landroid/app/usage/NetworkStats;->mEnumerationIndex:I
-Landroid/app/usage/NetworkStats;->mHistory:Landroid/net/NetworkStatsHistory;
-Landroid/app/usage/NetworkStats;->mRecycledHistoryEntry:Landroid/net/NetworkStatsHistory$Entry;
-Landroid/app/usage/NetworkStats;->mRecycledSummaryEntry:Landroid/net/NetworkStats$Entry;
-Landroid/app/usage/NetworkStats;->mSession:Landroid/net/INetworkStatsSession;
-Landroid/app/usage/NetworkStats;->mStartTimeStamp:J
-Landroid/app/usage/NetworkStats;->mState:I
-Landroid/app/usage/NetworkStats;->mSummary:Landroid/net/NetworkStats;
-Landroid/app/usage/NetworkStats;->mTag:I
-Landroid/app/usage/NetworkStats;->mTemplate:Landroid/net/NetworkTemplate;
-Landroid/app/usage/NetworkStats;->mUidOrUidIndex:I
-Landroid/app/usage/NetworkStats;->mUids:[I
-Landroid/app/usage/NetworkStats;->setSingleUidTagState(III)V
-Landroid/app/usage/NetworkStats;->startHistoryEnumeration(III)V
-Landroid/app/usage/NetworkStats;->startSummaryEnumeration()V
-Landroid/app/usage/NetworkStats;->startUserUidEnumeration()V
-Landroid/app/usage/NetworkStats;->stepHistory()V
-Landroid/app/usage/NetworkStats;->stepUid()V
-Landroid/app/usage/NetworkStats;->TAG:Ljava/lang/String;
-Landroid/app/usage/NetworkStatsManager$CallbackHandler;-><init>(Landroid/os/Looper;ILjava/lang/String;Landroid/app/usage/NetworkStatsManager$UsageCallback;)V
-Landroid/app/usage/NetworkStatsManager$CallbackHandler;->getObject(Landroid/os/Message;Ljava/lang/String;)Ljava/lang/Object;
-Landroid/app/usage/NetworkStatsManager$CallbackHandler;->mCallback:Landroid/app/usage/NetworkStatsManager$UsageCallback;
-Landroid/app/usage/NetworkStatsManager$CallbackHandler;->mNetworkType:I
-Landroid/app/usage/NetworkStatsManager$CallbackHandler;->mSubscriberId:Ljava/lang/String;
-Landroid/app/usage/NetworkStatsManager$UsageCallback;->request:Landroid/net/DataUsageRequest;
-Landroid/app/usage/NetworkStatsManager;-><init>(Landroid/content/Context;Landroid/net/INetworkStatsService;)V
-Landroid/app/usage/NetworkStatsManager;->CALLBACK_LIMIT_REACHED:I
-Landroid/app/usage/NetworkStatsManager;->CALLBACK_RELEASED:I
-Landroid/app/usage/NetworkStatsManager;->createTemplate(ILjava/lang/String;)Landroid/net/NetworkTemplate;
-Landroid/app/usage/NetworkStatsManager;->DBG:Z
-Landroid/app/usage/NetworkStatsManager;->FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN:I
-Landroid/app/usage/NetworkStatsManager;->FLAG_POLL_FORCE:I
-Landroid/app/usage/NetworkStatsManager;->FLAG_POLL_ON_OPEN:I
-Landroid/app/usage/NetworkStatsManager;->mContext:Landroid/content/Context;
-Landroid/app/usage/NetworkStatsManager;->mFlags:I
-Landroid/app/usage/NetworkStatsManager;->MIN_THRESHOLD_BYTES:J
-Landroid/app/usage/NetworkStatsManager;->mService:Landroid/net/INetworkStatsService;
-Landroid/app/usage/NetworkStatsManager;->querySummaryForDevice(Landroid/net/NetworkTemplate;JJ)Landroid/app/usage/NetworkStats$Bucket;
-Landroid/app/usage/NetworkStatsManager;->registerUsageCallback(Landroid/net/NetworkTemplate;IJLandroid/app/usage/NetworkStatsManager$UsageCallback;Landroid/os/Handler;)V
-Landroid/app/usage/NetworkStatsManager;->setAugmentWithSubscriptionPlan(Z)V
-Landroid/app/usage/NetworkStatsManager;->setPollOnOpen(Z)V
-Landroid/app/usage/NetworkStatsManager;->TAG:Ljava/lang/String;
 Landroid/app/usage/StorageStats;-><init>()V
 Landroid/app/usage/StorageStats;-><init>(Landroid/os/Parcel;)V
 Landroid/app/usage/StorageStats;->cacheBytes:J
@@ -35338,13 +35266,6 @@
 Landroid/net/Credentials;->gid:I
 Landroid/net/Credentials;->pid:I
 Landroid/net/Credentials;->uid:I
-Landroid/net/DataUsageRequest;-><init>(ILandroid/net/NetworkTemplate;J)V
-Landroid/net/DataUsageRequest;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/DataUsageRequest;->PARCELABLE_KEY:Ljava/lang/String;
-Landroid/net/DataUsageRequest;->requestId:I
-Landroid/net/DataUsageRequest;->REQUEST_ID_UNSET:I
-Landroid/net/DataUsageRequest;->template:Landroid/net/NetworkTemplate;
-Landroid/net/DataUsageRequest;->thresholdInBytes:J
 Landroid/net/DhcpResults;->addDns(Ljava/lang/String;)Z
 Landroid/net/DhcpResults;->clear()V
 Landroid/net/DhcpResults;->CREATOR:Landroid/os/Parcelable$Creator;
@@ -35446,51 +35367,6 @@
 Landroid/net/IIpConnectivityMetrics;->addNetdEventCallback(ILandroid/net/INetdEventCallback;)Z
 Landroid/net/IIpConnectivityMetrics;->logEvent(Landroid/net/ConnectivityMetricsEvent;)I
 Landroid/net/IIpConnectivityMetrics;->removeNetdEventCallback(I)Z
-Landroid/net/IIpSecService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/IIpSecService$Stub$Proxy;->addAddressToTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
-Landroid/net/IIpSecService$Stub$Proxy;->allocateSecurityParameterIndex(Ljava/lang/String;ILandroid/os/IBinder;)Landroid/net/IpSecSpiResponse;
-Landroid/net/IIpSecService$Stub$Proxy;->applyTransportModeTransform(Landroid/os/ParcelFileDescriptor;II)V
-Landroid/net/IIpSecService$Stub$Proxy;->applyTunnelModeTransform(IIILjava/lang/String;)V
-Landroid/net/IIpSecService$Stub$Proxy;->closeUdpEncapsulationSocket(I)V
-Landroid/net/IIpSecService$Stub$Proxy;->createTransform(Landroid/net/IpSecConfig;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTransformResponse;
-Landroid/net/IIpSecService$Stub$Proxy;->createTunnelInterface(Ljava/lang/String;Ljava/lang/String;Landroid/net/Network;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTunnelInterfaceResponse;
-Landroid/net/IIpSecService$Stub$Proxy;->deleteTransform(I)V
-Landroid/net/IIpSecService$Stub$Proxy;->deleteTunnelInterface(ILjava/lang/String;)V
-Landroid/net/IIpSecService$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/IIpSecService$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/IIpSecService$Stub$Proxy;->openUdpEncapsulationSocket(ILandroid/os/IBinder;)Landroid/net/IpSecUdpEncapResponse;
-Landroid/net/IIpSecService$Stub$Proxy;->releaseSecurityParameterIndex(I)V
-Landroid/net/IIpSecService$Stub$Proxy;->removeAddressFromTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
-Landroid/net/IIpSecService$Stub$Proxy;->removeTransportModeTransforms(Landroid/os/ParcelFileDescriptor;)V
-Landroid/net/IIpSecService$Stub;-><init>()V
-Landroid/net/IIpSecService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IIpSecService;
-Landroid/net/IIpSecService$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/IIpSecService$Stub;->TRANSACTION_addAddressToTunnelInterface:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_allocateSecurityParameterIndex:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_applyTransportModeTransform:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_applyTunnelModeTransform:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_closeUdpEncapsulationSocket:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_createTransform:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_createTunnelInterface:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_deleteTransform:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_deleteTunnelInterface:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_openUdpEncapsulationSocket:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_releaseSecurityParameterIndex:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_removeAddressFromTunnelInterface:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_removeTransportModeTransforms:I
-Landroid/net/IIpSecService;->addAddressToTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
-Landroid/net/IIpSecService;->allocateSecurityParameterIndex(Ljava/lang/String;ILandroid/os/IBinder;)Landroid/net/IpSecSpiResponse;
-Landroid/net/IIpSecService;->applyTransportModeTransform(Landroid/os/ParcelFileDescriptor;II)V
-Landroid/net/IIpSecService;->applyTunnelModeTransform(IIILjava/lang/String;)V
-Landroid/net/IIpSecService;->closeUdpEncapsulationSocket(I)V
-Landroid/net/IIpSecService;->createTransform(Landroid/net/IpSecConfig;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTransformResponse;
-Landroid/net/IIpSecService;->createTunnelInterface(Ljava/lang/String;Ljava/lang/String;Landroid/net/Network;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTunnelInterfaceResponse;
-Landroid/net/IIpSecService;->deleteTransform(I)V
-Landroid/net/IIpSecService;->deleteTunnelInterface(ILjava/lang/String;)V
-Landroid/net/IIpSecService;->openUdpEncapsulationSocket(ILandroid/os/IBinder;)Landroid/net/IpSecUdpEncapResponse;
-Landroid/net/IIpSecService;->releaseSecurityParameterIndex(I)V
-Landroid/net/IIpSecService;->removeAddressFromTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
-Landroid/net/IIpSecService;->removeTransportModeTransforms(Landroid/os/ParcelFileDescriptor;)V
 Landroid/net/INetd$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/net/INetd$Stub$Proxy;->addVirtualTunnelInterface(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V
 Landroid/net/INetd$Stub$Proxy;->bandwidthEnableDataSaver(Z)Z
@@ -35838,68 +35714,6 @@
 Landroid/net/INetworkScoreService;->setActiveScorer(Ljava/lang/String;)Z
 Landroid/net/INetworkScoreService;->unregisterNetworkScoreCache(ILandroid/net/INetworkScoreCache;)V
 Landroid/net/INetworkScoreService;->updateScores([Landroid/net/ScoredNetwork;)Z
-Landroid/net/INetworkStatsService$Stub$Proxy;->forceUpdate()V
-Landroid/net/INetworkStatsService$Stub$Proxy;->forceUpdateIfaces([Landroid/net/Network;)V
-Landroid/net/INetworkStatsService$Stub$Proxy;->getDataLayerSnapshotForUid(I)Landroid/net/NetworkStats;
-Landroid/net/INetworkStatsService$Stub$Proxy;->getDetailedUidStats([Ljava/lang/String;)Landroid/net/NetworkStats;
-Landroid/net/INetworkStatsService$Stub$Proxy;->getIfaceStats(Ljava/lang/String;I)J
-Landroid/net/INetworkStatsService$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/INetworkStatsService$Stub$Proxy;->getTotalStats(I)J
-Landroid/net/INetworkStatsService$Stub$Proxy;->getUidStats(II)J
-Landroid/net/INetworkStatsService$Stub$Proxy;->incrementOperationCount(III)V
-Landroid/net/INetworkStatsService$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/INetworkStatsService$Stub$Proxy;->openSession()Landroid/net/INetworkStatsSession;
-Landroid/net/INetworkStatsService$Stub$Proxy;->openSessionForUsageStats(ILjava/lang/String;)Landroid/net/INetworkStatsSession;
-Landroid/net/INetworkStatsService$Stub$Proxy;->registerUsageCallback(Ljava/lang/String;Landroid/net/DataUsageRequest;Landroid/os/Messenger;Landroid/os/IBinder;)Landroid/net/DataUsageRequest;
-Landroid/net/INetworkStatsService$Stub$Proxy;->unregisterUsageRequest(Landroid/net/DataUsageRequest;)V
-Landroid/net/INetworkStatsService$Stub;-><init>()V
-Landroid/net/INetworkStatsService$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_forceUpdate:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_forceUpdateIfaces:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getDataLayerSnapshotForUid:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getDetailedUidStats:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getIfaceStats:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getMobileIfaces:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getTotalStats:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_getUidStats:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_incrementOperationCount:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_openSession:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_openSessionForUsageStats:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_registerUsageCallback:I
-Landroid/net/INetworkStatsService$Stub;->TRANSACTION_unregisterUsageRequest:I
-Landroid/net/INetworkStatsService;->forceUpdateIfaces([Landroid/net/Network;)V
-Landroid/net/INetworkStatsService;->getDetailedUidStats([Ljava/lang/String;)Landroid/net/NetworkStats;
-Landroid/net/INetworkStatsService;->getIfaceStats(Ljava/lang/String;I)J
-Landroid/net/INetworkStatsService;->getTotalStats(I)J
-Landroid/net/INetworkStatsService;->getUidStats(II)J
-Landroid/net/INetworkStatsService;->incrementOperationCount(III)V
-Landroid/net/INetworkStatsService;->registerUsageCallback(Ljava/lang/String;Landroid/net/DataUsageRequest;Landroid/os/Messenger;Landroid/os/IBinder;)Landroid/net/DataUsageRequest;
-Landroid/net/INetworkStatsService;->unregisterUsageRequest(Landroid/net/DataUsageRequest;)V
-Landroid/net/INetworkStatsSession$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/INetworkStatsSession$Stub$Proxy;->close()V
-Landroid/net/INetworkStatsSession$Stub$Proxy;->getDeviceSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats;
-Landroid/net/INetworkStatsSession$Stub$Proxy;->getHistoryForNetwork(Landroid/net/NetworkTemplate;I)Landroid/net/NetworkStatsHistory;
-Landroid/net/INetworkStatsSession$Stub$Proxy;->getHistoryForUid(Landroid/net/NetworkTemplate;IIII)Landroid/net/NetworkStatsHistory;
-Landroid/net/INetworkStatsSession$Stub$Proxy;->getHistoryIntervalForUid(Landroid/net/NetworkTemplate;IIIIJJ)Landroid/net/NetworkStatsHistory;
-Landroid/net/INetworkStatsSession$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/INetworkStatsSession$Stub$Proxy;->getRelevantUids()[I
-Landroid/net/INetworkStatsSession$Stub$Proxy;->getSummaryForAllUid(Landroid/net/NetworkTemplate;JJZ)Landroid/net/NetworkStats;
-Landroid/net/INetworkStatsSession$Stub$Proxy;->getSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats;
-Landroid/net/INetworkStatsSession$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/INetworkStatsSession$Stub;-><init>()V
-Landroid/net/INetworkStatsSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsSession;
-Landroid/net/INetworkStatsSession$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_close:I
-Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getDeviceSummaryForNetwork:I
-Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getHistoryForNetwork:I
-Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getHistoryForUid:I
-Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getHistoryIntervalForUid:I
-Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getRelevantUids:I
-Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getSummaryForAllUid:I
-Landroid/net/INetworkStatsSession$Stub;->TRANSACTION_getSummaryForNetwork:I
-Landroid/net/INetworkStatsSession;->getDeviceSummaryForNetwork(Landroid/net/NetworkTemplate;JJ)Landroid/net/NetworkStats;
-Landroid/net/INetworkStatsSession;->getHistoryIntervalForUid(Landroid/net/NetworkTemplate;IIIIJJ)Landroid/net/NetworkStatsHistory;
-Landroid/net/INetworkStatsSession;->getRelevantUids()[I
 Landroid/net/InterfaceConfiguration;->CREATOR:Landroid/os/Parcelable$Creator;
 Landroid/net/InterfaceConfiguration;->FLAG_DOWN:Ljava/lang/String;
 Landroid/net/InterfaceConfiguration;->FLAG_UP:Ljava/lang/String;
@@ -35914,174 +35728,6 @@
 Landroid/net/InterfaceConfiguration;->mHwAddr:Ljava/lang/String;
 Landroid/net/InterfaceConfiguration;->setHardwareAddress(Ljava/lang/String;)V
 Landroid/net/InterfaceConfiguration;->validateFlag(Ljava/lang/String;)V
-Landroid/net/IpSecAlgorithm;->checkValidOrThrow(Ljava/lang/String;II)V
-Landroid/net/IpSecAlgorithm;->CRYPT_NULL:Ljava/lang/String;
-Landroid/net/IpSecAlgorithm;->equals(Landroid/net/IpSecAlgorithm;Landroid/net/IpSecAlgorithm;)Z
-Landroid/net/IpSecAlgorithm;->isAead()Z
-Landroid/net/IpSecAlgorithm;->isAuthentication()Z
-Landroid/net/IpSecAlgorithm;->isEncryption()Z
-Landroid/net/IpSecAlgorithm;->isUnsafeBuild()Z
-Landroid/net/IpSecAlgorithm;->mKey:[B
-Landroid/net/IpSecAlgorithm;->mName:Ljava/lang/String;
-Landroid/net/IpSecAlgorithm;->mTruncLenBits:I
-Landroid/net/IpSecAlgorithm;->TAG:Ljava/lang/String;
-Landroid/net/IpSecConfig;-><init>()V
-Landroid/net/IpSecConfig;-><init>(Landroid/net/IpSecConfig;)V
-Landroid/net/IpSecConfig;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecConfig;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecConfig;->equals(Landroid/net/IpSecConfig;Landroid/net/IpSecConfig;)Z
-Landroid/net/IpSecConfig;->getAuthenticatedEncryption()Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->getAuthentication()Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->getDestinationAddress()Ljava/lang/String;
-Landroid/net/IpSecConfig;->getEncapRemotePort()I
-Landroid/net/IpSecConfig;->getEncapSocketResourceId()I
-Landroid/net/IpSecConfig;->getEncapType()I
-Landroid/net/IpSecConfig;->getEncryption()Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->getMarkMask()I
-Landroid/net/IpSecConfig;->getMarkValue()I
-Landroid/net/IpSecConfig;->getMode()I
-Landroid/net/IpSecConfig;->getNattKeepaliveInterval()I
-Landroid/net/IpSecConfig;->getNetwork()Landroid/net/Network;
-Landroid/net/IpSecConfig;->getSourceAddress()Ljava/lang/String;
-Landroid/net/IpSecConfig;->getSpiResourceId()I
-Landroid/net/IpSecConfig;->mAuthenticatedEncryption:Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->mAuthentication:Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->mDestinationAddress:Ljava/lang/String;
-Landroid/net/IpSecConfig;->mEncapRemotePort:I
-Landroid/net/IpSecConfig;->mEncapSocketResourceId:I
-Landroid/net/IpSecConfig;->mEncapType:I
-Landroid/net/IpSecConfig;->mEncryption:Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->mMarkMask:I
-Landroid/net/IpSecConfig;->mMarkValue:I
-Landroid/net/IpSecConfig;->mMode:I
-Landroid/net/IpSecConfig;->mNattKeepaliveInterval:I
-Landroid/net/IpSecConfig;->mNetwork:Landroid/net/Network;
-Landroid/net/IpSecConfig;->mSourceAddress:Ljava/lang/String;
-Landroid/net/IpSecConfig;->mSpiResourceId:I
-Landroid/net/IpSecConfig;->setAuthenticatedEncryption(Landroid/net/IpSecAlgorithm;)V
-Landroid/net/IpSecConfig;->setAuthentication(Landroid/net/IpSecAlgorithm;)V
-Landroid/net/IpSecConfig;->setDestinationAddress(Ljava/lang/String;)V
-Landroid/net/IpSecConfig;->setEncapRemotePort(I)V
-Landroid/net/IpSecConfig;->setEncapSocketResourceId(I)V
-Landroid/net/IpSecConfig;->setEncapType(I)V
-Landroid/net/IpSecConfig;->setEncryption(Landroid/net/IpSecAlgorithm;)V
-Landroid/net/IpSecConfig;->setMarkMask(I)V
-Landroid/net/IpSecConfig;->setMarkValue(I)V
-Landroid/net/IpSecConfig;->setMode(I)V
-Landroid/net/IpSecConfig;->setNattKeepaliveInterval(I)V
-Landroid/net/IpSecConfig;->setNetwork(Landroid/net/Network;)V
-Landroid/net/IpSecConfig;->setSourceAddress(Ljava/lang/String;)V
-Landroid/net/IpSecConfig;->setSpiResourceId(I)V
-Landroid/net/IpSecConfig;->TAG:Ljava/lang/String;
-Landroid/net/IpSecManager$IpSecTunnelInterface;-><init>(Landroid/content/Context;Landroid/net/IIpSecService;Ljava/net/InetAddress;Ljava/net/InetAddress;Landroid/net/Network;)V
-Landroid/net/IpSecManager$IpSecTunnelInterface;->addAddress(Ljava/net/InetAddress;I)V
-Landroid/net/IpSecManager$IpSecTunnelInterface;->getInterfaceName()Ljava/lang/String;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->getResourceId()I
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mCloseGuard:Ldalvik/system/CloseGuard;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mInterfaceName:Ljava/lang/String;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mLocalAddress:Ljava/net/InetAddress;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mOpPackageName:Ljava/lang/String;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mRemoteAddress:Ljava/net/InetAddress;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mResourceId:I
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mService:Landroid/net/IIpSecService;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mUnderlyingNetwork:Landroid/net/Network;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->removeAddress(Ljava/net/InetAddress;I)V
-Landroid/net/IpSecManager$ResourceUnavailableException;-><init>(Ljava/lang/String;)V
-Landroid/net/IpSecManager$SecurityParameterIndex;-><init>(Landroid/net/IIpSecService;Ljava/net/InetAddress;I)V
-Landroid/net/IpSecManager$SecurityParameterIndex;->getResourceId()I
-Landroid/net/IpSecManager$SecurityParameterIndex;->mCloseGuard:Ldalvik/system/CloseGuard;
-Landroid/net/IpSecManager$SecurityParameterIndex;->mDestinationAddress:Ljava/net/InetAddress;
-Landroid/net/IpSecManager$SecurityParameterIndex;->mResourceId:I
-Landroid/net/IpSecManager$SecurityParameterIndex;->mService:Landroid/net/IIpSecService;
-Landroid/net/IpSecManager$SecurityParameterIndex;->mSpi:I
-Landroid/net/IpSecManager$SpiUnavailableException;-><init>(Ljava/lang/String;I)V
-Landroid/net/IpSecManager$SpiUnavailableException;->mSpi:I
-Landroid/net/IpSecManager$Status;->OK:I
-Landroid/net/IpSecManager$Status;->RESOURCE_UNAVAILABLE:I
-Landroid/net/IpSecManager$Status;->SPI_UNAVAILABLE:I
-Landroid/net/IpSecManager$UdpEncapsulationSocket;-><init>(Landroid/net/IIpSecService;I)V
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->getResourceId()I
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mCloseGuard:Ldalvik/system/CloseGuard;
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mPfd:Landroid/os/ParcelFileDescriptor;
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mPort:I
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mResourceId:I
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mService:Landroid/net/IIpSecService;
-Landroid/net/IpSecManager;-><init>(Landroid/content/Context;Landroid/net/IIpSecService;)V
-Landroid/net/IpSecManager;->applyTunnelModeTransform(Landroid/net/IpSecManager$IpSecTunnelInterface;ILandroid/net/IpSecTransform;)V
-Landroid/net/IpSecManager;->createIpSecTunnelInterface(Ljava/net/InetAddress;Ljava/net/InetAddress;Landroid/net/Network;)Landroid/net/IpSecManager$IpSecTunnelInterface;
-Landroid/net/IpSecManager;->INVALID_RESOURCE_ID:I
-Landroid/net/IpSecManager;->maybeHandleServiceSpecificException(Landroid/os/ServiceSpecificException;)V
-Landroid/net/IpSecManager;->mContext:Landroid/content/Context;
-Landroid/net/IpSecManager;->mService:Landroid/net/IIpSecService;
-Landroid/net/IpSecManager;->removeTunnelModeTransform(Landroid/net/Network;Landroid/net/IpSecTransform;)V
-Landroid/net/IpSecManager;->rethrowCheckedExceptionFromServiceSpecificException(Landroid/os/ServiceSpecificException;)Ljava/io/IOException;
-Landroid/net/IpSecManager;->rethrowUncheckedExceptionFromServiceSpecificException(Landroid/os/ServiceSpecificException;)Ljava/lang/RuntimeException;
-Landroid/net/IpSecManager;->TAG:Ljava/lang/String;
-Landroid/net/IpSecSpiResponse;-><init>(I)V
-Landroid/net/IpSecSpiResponse;-><init>(III)V
-Landroid/net/IpSecSpiResponse;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecSpiResponse;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecSpiResponse;->resourceId:I
-Landroid/net/IpSecSpiResponse;->spi:I
-Landroid/net/IpSecSpiResponse;->status:I
-Landroid/net/IpSecSpiResponse;->TAG:Ljava/lang/String;
-Landroid/net/IpSecTransform$Builder;->buildTunnelModeTransform(Ljava/net/InetAddress;Landroid/net/IpSecManager$SecurityParameterIndex;)Landroid/net/IpSecTransform;
-Landroid/net/IpSecTransform$Builder;->mConfig:Landroid/net/IpSecConfig;
-Landroid/net/IpSecTransform$Builder;->mContext:Landroid/content/Context;
-Landroid/net/IpSecTransform$NattKeepaliveCallback;-><init>()V
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_HARDWARE_ERROR:I
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_HARDWARE_UNSUPPORTED:I
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_INVALID_NETWORK:I
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->onError(I)V
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->onStarted()V
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->onStopped()V
-Landroid/net/IpSecTransform;-><init>(Landroid/content/Context;Landroid/net/IpSecConfig;)V
-Landroid/net/IpSecTransform;->activate()Landroid/net/IpSecTransform;
-Landroid/net/IpSecTransform;->checkResultStatus(I)V
-Landroid/net/IpSecTransform;->ENCAP_ESPINUDP:I
-Landroid/net/IpSecTransform;->ENCAP_ESPINUDP_NON_IKE:I
-Landroid/net/IpSecTransform;->ENCAP_NONE:I
-Landroid/net/IpSecTransform;->equals(Landroid/net/IpSecTransform;Landroid/net/IpSecTransform;)Z
-Landroid/net/IpSecTransform;->getConfig()Landroid/net/IpSecConfig;
-Landroid/net/IpSecTransform;->getIpSecService()Landroid/net/IIpSecService;
-Landroid/net/IpSecTransform;->getResourceId()I
-Landroid/net/IpSecTransform;->mCallbackHandler:Landroid/os/Handler;
-Landroid/net/IpSecTransform;->mCloseGuard:Ldalvik/system/CloseGuard;
-Landroid/net/IpSecTransform;->mConfig:Landroid/net/IpSecConfig;
-Landroid/net/IpSecTransform;->mContext:Landroid/content/Context;
-Landroid/net/IpSecTransform;->mKeepalive:Landroid/net/ConnectivityManager$PacketKeepalive;
-Landroid/net/IpSecTransform;->mKeepaliveCallback:Landroid/net/ConnectivityManager$PacketKeepaliveCallback;
-Landroid/net/IpSecTransform;->MODE_TRANSPORT:I
-Landroid/net/IpSecTransform;->MODE_TUNNEL:I
-Landroid/net/IpSecTransform;->mResourceId:I
-Landroid/net/IpSecTransform;->mUserKeepaliveCallback:Landroid/net/IpSecTransform$NattKeepaliveCallback;
-Landroid/net/IpSecTransform;->startNattKeepalive(Landroid/net/IpSecTransform$NattKeepaliveCallback;ILandroid/os/Handler;)V
-Landroid/net/IpSecTransform;->stopNattKeepalive()V
-Landroid/net/IpSecTransform;->TAG:Ljava/lang/String;
-Landroid/net/IpSecTransformResponse;-><init>(I)V
-Landroid/net/IpSecTransformResponse;-><init>(II)V
-Landroid/net/IpSecTransformResponse;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecTransformResponse;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecTransformResponse;->resourceId:I
-Landroid/net/IpSecTransformResponse;->status:I
-Landroid/net/IpSecTransformResponse;->TAG:Ljava/lang/String;
-Landroid/net/IpSecTunnelInterfaceResponse;-><init>(I)V
-Landroid/net/IpSecTunnelInterfaceResponse;-><init>(IILjava/lang/String;)V
-Landroid/net/IpSecTunnelInterfaceResponse;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecTunnelInterfaceResponse;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecTunnelInterfaceResponse;->interfaceName:Ljava/lang/String;
-Landroid/net/IpSecTunnelInterfaceResponse;->resourceId:I
-Landroid/net/IpSecTunnelInterfaceResponse;->status:I
-Landroid/net/IpSecTunnelInterfaceResponse;->TAG:Ljava/lang/String;
-Landroid/net/IpSecUdpEncapResponse;-><init>(I)V
-Landroid/net/IpSecUdpEncapResponse;-><init>(IIILjava/io/FileDescriptor;)V
-Landroid/net/IpSecUdpEncapResponse;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecUdpEncapResponse;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecUdpEncapResponse;->fileDescriptor:Landroid/os/ParcelFileDescriptor;
-Landroid/net/IpSecUdpEncapResponse;->port:I
-Landroid/net/IpSecUdpEncapResponse;->resourceId:I
-Landroid/net/IpSecUdpEncapResponse;->status:I
-Landroid/net/IpSecUdpEncapResponse;->TAG:Ljava/lang/String;
 Landroid/net/ITetheringStatsProvider$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/net/ITetheringStatsProvider$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
 Landroid/net/ITetheringStatsProvider$Stub$Proxy;->getTetherStats(I)Landroid/net/NetworkStats;
@@ -36742,41 +36388,6 @@
 Landroid/net/StringNetworkSpecifier;-><init>(Ljava/lang/String;)V
 Landroid/net/StringNetworkSpecifier;->CREATOR:Landroid/os/Parcelable$Creator;
 Landroid/net/StringNetworkSpecifier;->satisfiedBy(Landroid/net/NetworkSpecifier;)Z
-Landroid/net/TrafficStats;->addIfSupported(J)J
-Landroid/net/TrafficStats;->closeQuietly(Landroid/net/INetworkStatsSession;)V
-Landroid/net/TrafficStats;->GB_IN_BYTES:J
-Landroid/net/TrafficStats;->getDataLayerSnapshotForUid(Landroid/content/Context;)Landroid/net/NetworkStats;
-Landroid/net/TrafficStats;->getRxPackets(Ljava/lang/String;)J
-Landroid/net/TrafficStats;->getTxPackets(Ljava/lang/String;)J
-Landroid/net/TrafficStats;->KB_IN_BYTES:J
-Landroid/net/TrafficStats;->LOOPBACK_IFACE:Ljava/lang/String;
-Landroid/net/TrafficStats;->MB_IN_BYTES:J
-Landroid/net/TrafficStats;->PB_IN_BYTES:J
-Landroid/net/TrafficStats;->sActiveProfilingStart:Landroid/net/NetworkStats;
-Landroid/net/TrafficStats;->sProfilingLock:Ljava/lang/Object;
-Landroid/net/TrafficStats;->sStatsService:Landroid/net/INetworkStatsService;
-Landroid/net/TrafficStats;->startDataProfiling(Landroid/content/Context;)V
-Landroid/net/TrafficStats;->stopDataProfiling(Landroid/content/Context;)Landroid/net/NetworkStats;
-Landroid/net/TrafficStats;->TAG_SYSTEM_APP:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_BACKUP:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_DHCP:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_DOWNLOAD:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_GPS:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_MEDIA:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_NEIGHBOR:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_NTP:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_PAC:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_PROBE:I
-Landroid/net/TrafficStats;->TAG_SYSTEM_RESTORE:I
-Landroid/net/TrafficStats;->TB_IN_BYTES:J
-Landroid/net/TrafficStats;->TYPE_RX_BYTES:I
-Landroid/net/TrafficStats;->TYPE_RX_PACKETS:I
-Landroid/net/TrafficStats;->TYPE_TCP_RX_PACKETS:I
-Landroid/net/TrafficStats;->TYPE_TCP_TX_PACKETS:I
-Landroid/net/TrafficStats;->TYPE_TX_BYTES:I
-Landroid/net/TrafficStats;->TYPE_TX_PACKETS:I
-Landroid/net/TrafficStats;->UID_REMOVED:I
-Landroid/net/TrafficStats;->UID_TETHERING:I
 Landroid/net/Uri$AbstractHierarchicalUri;-><init>()V
 Landroid/net/Uri$AbstractHierarchicalUri;->getUserInfoPart()Landroid/net/Uri$Part;
 Landroid/net/Uri$AbstractHierarchicalUri;->host:Ljava/lang/String;
diff --git a/boot/hiddenapi/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt
index 522e88f..033afb6 100644
--- a/boot/hiddenapi/hiddenapi-unsupported.txt
+++ b/boot/hiddenapi/hiddenapi-unsupported.txt
@@ -168,9 +168,6 @@
 Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V
 Landroid/net/INetworkPolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkPolicyManager;
 Landroid/net/INetworkScoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkScoreService;
-Landroid/net/INetworkStatsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String;
-Landroid/net/INetworkStatsService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsService;
 Landroid/os/IBatteryPropertiesRegistrar$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/os/IDeviceIdentifiersPolicyService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdentifiersPolicyService;
 Landroid/os/IDeviceIdleController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdleController;
diff --git a/core/api/current.txt b/core/api/current.txt
index 4777e3c..fd53d88 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -135,6 +135,9 @@
     field public static final String READ_HOME_APP_SEARCH_DATA = "android.permission.READ_HOME_APP_SEARCH_DATA";
     field @Deprecated public static final String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
     field public static final String READ_LOGS = "android.permission.READ_LOGS";
+    field public static final String READ_MEDIA_AUDIO = "android.permission.READ_MEDIA_AUDIO";
+    field public static final String READ_MEDIA_IMAGE = "android.permission.READ_MEDIA_IMAGE";
+    field public static final String READ_MEDIA_VIDEO = "android.permission.READ_MEDIA_VIDEO";
     field public static final String READ_NEARBY_STREAMING_POLICY = "android.permission.READ_NEARBY_STREAMING_POLICY";
     field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
     field public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
@@ -220,6 +223,8 @@
     field public static final String NEARBY_DEVICES = "android.permission-group.NEARBY_DEVICES";
     field public static final String NOTIFICATIONS = "android.permission-group.NOTIFICATIONS";
     field public static final String PHONE = "android.permission-group.PHONE";
+    field public static final String READ_MEDIA_AURAL = "android.permission-group.READ_MEDIA_AURAL";
+    field public static final String READ_MEDIA_VISUAL = "android.permission-group.READ_MEDIA_VISUAL";
     field public static final String SENSORS = "android.permission-group.SENSORS";
     field public static final String SMS = "android.permission-group.SMS";
     field public static final String STORAGE = "android.permission-group.STORAGE";
@@ -3074,6 +3079,7 @@
     method public void onSystemActionsChanged();
     method public final boolean performGlobalAction(int);
     method public void setAccessibilityFocusAppearance(int, @ColorInt int);
+    method public void setAnimationScale(float);
     method public boolean setCacheEnabled(boolean);
     method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region);
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
@@ -3591,17 +3597,17 @@
   }
 
   public static interface Animator.AnimatorListener {
-    method public void onAnimationCancel(android.animation.Animator);
-    method public default void onAnimationEnd(android.animation.Animator, boolean);
-    method public void onAnimationEnd(android.animation.Animator);
-    method public void onAnimationRepeat(android.animation.Animator);
-    method public default void onAnimationStart(android.animation.Animator, boolean);
-    method public void onAnimationStart(android.animation.Animator);
+    method public void onAnimationCancel(@NonNull android.animation.Animator);
+    method public default void onAnimationEnd(@NonNull android.animation.Animator, boolean);
+    method public void onAnimationEnd(@NonNull android.animation.Animator);
+    method public void onAnimationRepeat(@NonNull android.animation.Animator);
+    method public default void onAnimationStart(@NonNull android.animation.Animator, boolean);
+    method public void onAnimationStart(@NonNull android.animation.Animator);
   }
 
   public static interface Animator.AnimatorPauseListener {
-    method public void onAnimationPause(android.animation.Animator);
-    method public void onAnimationResume(android.animation.Animator);
+    method public void onAnimationPause(@NonNull android.animation.Animator);
+    method public void onAnimationResume(@NonNull android.animation.Animator);
   }
 
   public class AnimatorInflater {
@@ -3888,7 +3894,7 @@
   }
 
   public static interface ValueAnimator.AnimatorUpdateListener {
-    method public void onAnimationUpdate(android.animation.ValueAnimator);
+    method public void onAnimationUpdate(@NonNull android.animation.ValueAnimator);
   }
 
 }
@@ -4069,7 +4075,7 @@
     method public int getMaxNumPictureInPictureActions();
     method public final android.media.session.MediaController getMediaController();
     method @NonNull public android.view.MenuInflater getMenuInflater();
-    method @Nullable public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
+    method @NonNull public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
     method public final android.app.Activity getParent();
     method @Nullable public android.content.Intent getParentActivityIntent();
     method public android.content.SharedPreferences getPreferences(int);
@@ -4875,6 +4881,7 @@
     field public static final int REASON_DEPENDENCY_DIED = 12; // 0xc
     field public static final int REASON_EXCESSIVE_RESOURCE_USAGE = 9; // 0x9
     field public static final int REASON_EXIT_SELF = 1; // 0x1
+    field public static final int REASON_FREEZER = 14; // 0xe
     field public static final int REASON_INITIALIZATION_FAILURE = 7; // 0x7
     field public static final int REASON_LOW_MEMORY = 3; // 0x3
     field public static final int REASON_OTHER = 13; // 0xd
@@ -4970,7 +4977,7 @@
     method @NonNull @UiContext public final android.content.Context getContext();
     method @Nullable public android.view.View getCurrentFocus();
     method @NonNull public android.view.LayoutInflater getLayoutInflater();
-    method @Nullable public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
+    method @NonNull public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
     method @Nullable public final android.app.Activity getOwnerActivity();
     method @Nullable public final android.view.SearchEvent getSearchEvent();
     method public final int getVolumeControlStream();
@@ -6949,6 +6956,7 @@
     method public boolean performGlobalAction(int);
     method public void revokeRuntimePermission(String, String);
     method public void revokeRuntimePermissionAsUser(String, String, android.os.UserHandle);
+    method public void setAnimationScale(float);
     method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
     method public boolean setRotation(int);
     method public void setRunAsMonkey(boolean);
@@ -7326,6 +7334,8 @@
     method public CharSequence getDeviceOwnerLockScreenInfo();
     method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
     method @Nullable public android.graphics.drawable.Drawable getDrawable(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
+    method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
+    method @Nullable public android.graphics.drawable.Icon getDrawableAsIcon(@NonNull String, @NonNull String, @Nullable android.graphics.drawable.Icon);
     method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
     method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
     method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName);
@@ -7611,7 +7621,7 @@
     field public static final String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
-    field public static final String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
+    field @Deprecated public static final String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
     field @Deprecated public static final String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
     field public static final String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
     field public static final String EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT = "android.app.extra.PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT";
@@ -7930,11 +7940,10 @@
   }
 
   public final class WifiSsidPolicy implements android.os.Parcelable {
-    method @NonNull public static android.app.admin.WifiSsidPolicy createAllowlistPolicy(@NonNull java.util.Set<java.lang.String>);
-    method @NonNull public static android.app.admin.WifiSsidPolicy createDenylistPolicy(@NonNull java.util.Set<java.lang.String>);
+    ctor public WifiSsidPolicy(int, @NonNull java.util.Set<android.net.wifi.WifiSsid>);
     method public int describeContents();
     method public int getPolicyType();
-    method @NonNull public java.util.Set<java.lang.String> getSsids();
+    method @NonNull public java.util.Set<android.net.wifi.WifiSsid> getSsids();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.WifiSsidPolicy> CREATOR;
     field public static final int WIFI_SSID_POLICY_TYPE_ALLOWLIST = 0; // 0x0
@@ -8591,62 +8600,6 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.usage.ExternalStorageStats> CREATOR;
   }
 
-  public final class NetworkStats implements java.lang.AutoCloseable {
-    method public void close();
-    method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket);
-    method public boolean hasNextBucket();
-  }
-
-  public static class NetworkStats.Bucket {
-    ctor public NetworkStats.Bucket();
-    method public int getDefaultNetworkStatus();
-    method public long getEndTimeStamp();
-    method public int getMetered();
-    method public int getRoaming();
-    method public long getRxBytes();
-    method public long getRxPackets();
-    method public long getStartTimeStamp();
-    method public int getState();
-    method public int getTag();
-    method public long getTxBytes();
-    method public long getTxPackets();
-    method public int getUid();
-    field public static final int DEFAULT_NETWORK_ALL = -1; // 0xffffffff
-    field public static final int DEFAULT_NETWORK_NO = 1; // 0x1
-    field public static final int DEFAULT_NETWORK_YES = 2; // 0x2
-    field public static final int METERED_ALL = -1; // 0xffffffff
-    field public static final int METERED_NO = 1; // 0x1
-    field public static final int METERED_YES = 2; // 0x2
-    field public static final int ROAMING_ALL = -1; // 0xffffffff
-    field public static final int ROAMING_NO = 1; // 0x1
-    field public static final int ROAMING_YES = 2; // 0x2
-    field public static final int STATE_ALL = -1; // 0xffffffff
-    field public static final int STATE_DEFAULT = 1; // 0x1
-    field public static final int STATE_FOREGROUND = 2; // 0x2
-    field public static final int TAG_NONE = 0; // 0x0
-    field public static final int UID_ALL = -1; // 0xffffffff
-    field public static final int UID_REMOVED = -4; // 0xfffffffc
-    field public static final int UID_TETHERING = -5; // 0xfffffffb
-  }
-
-  public class NetworkStatsManager {
-    method @WorkerThread public android.app.usage.NetworkStats queryDetails(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUid(int, String, long, long, int) throws java.lang.SecurityException;
-    method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTag(int, String, long, long, int, int) throws java.lang.SecurityException;
-    method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(int, String, long, long, int, int, int) throws java.lang.SecurityException;
-    method @WorkerThread public android.app.usage.NetworkStats querySummary(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback);
-    method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback, @Nullable android.os.Handler);
-    method public void unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback);
-  }
-
-  public abstract static class NetworkStatsManager.UsageCallback {
-    ctor public NetworkStatsManager.UsageCallback();
-    method public abstract void onThresholdReached(int, String);
-  }
-
   public final class StorageStats implements android.os.Parcelable {
     method public int describeContents();
     method public long getAppBytes();
@@ -11928,7 +11881,7 @@
     field public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
     field public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
     field public static final String FEATURE_TELEPHONY_MESSAGING = "android.hardware.telephony.messaging";
-    field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio";
+    field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access";
     field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription";
     field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television";
     field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
@@ -15466,8 +15419,6 @@
 
   public class RuntimeShader extends android.graphics.Shader {
     ctor public RuntimeShader(@NonNull String);
-    ctor public RuntimeShader(@NonNull String, boolean);
-    method public boolean isForceOpaque();
     method public void setColorUniform(@NonNull String, @ColorInt int);
     method public void setColorUniform(@NonNull String, @ColorLong long);
     method public void setColorUniform(@NonNull String, @NonNull android.graphics.Color);
@@ -15765,9 +15716,9 @@
     method public final void copyBounds(@NonNull android.graphics.Rect);
     method @NonNull public final android.graphics.Rect copyBounds();
     method @Nullable public static android.graphics.drawable.Drawable createFromPath(String);
-    method public static android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, String);
+    method @Nullable public static android.graphics.drawable.Drawable createFromResourceStream(@Nullable android.content.res.Resources, @Nullable android.util.TypedValue, @Nullable java.io.InputStream, @Nullable String);
     method @Deprecated @Nullable public static android.graphics.drawable.Drawable createFromResourceStream(@Nullable android.content.res.Resources, @Nullable android.util.TypedValue, @Nullable java.io.InputStream, @Nullable String, @Nullable android.graphics.BitmapFactory.Options);
-    method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, String);
+    method @Nullable public static android.graphics.drawable.Drawable createFromStream(@Nullable java.io.InputStream, @Nullable String);
     method @NonNull public static android.graphics.drawable.Drawable createFromXml(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method @NonNull public static android.graphics.drawable.Drawable createFromXml(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @Nullable android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method @NonNull public static android.graphics.drawable.Drawable createFromXmlInner(@NonNull android.content.res.Resources, @NonNull org.xmlpull.v1.XmlPullParser, @NonNull android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
@@ -15805,10 +15756,10 @@
     method public final boolean isVisible();
     method public void jumpToCurrentState();
     method @NonNull public android.graphics.drawable.Drawable mutate();
-    method protected void onBoundsChange(android.graphics.Rect);
+    method protected void onBoundsChange(@NonNull android.graphics.Rect);
     method public boolean onLayoutDirectionChanged(int);
     method protected boolean onLevelChange(int);
-    method protected boolean onStateChange(int[]);
+    method protected boolean onStateChange(@NonNull int[]);
     method public static int resolveOpacity(int, int);
     method public void scheduleSelf(@NonNull Runnable, long);
     method public abstract void setAlpha(@IntRange(from=0, to=255) int);
@@ -15969,27 +15920,27 @@
   }
 
   public final class Icon implements android.os.Parcelable {
-    method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
+    method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
     method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmapContentUri(@NonNull String);
     method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmapContentUri(@NonNull android.net.Uri);
-    method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
-    method public static android.graphics.drawable.Icon createWithContentUri(String);
-    method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
-    method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
-    method public static android.graphics.drawable.Icon createWithFilePath(String);
-    method public static android.graphics.drawable.Icon createWithResource(android.content.Context, @DrawableRes int);
-    method public static android.graphics.drawable.Icon createWithResource(String, @DrawableRes int);
+    method @NonNull public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
+    method @NonNull public static android.graphics.drawable.Icon createWithContentUri(String);
+    method @NonNull public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
+    method @NonNull public static android.graphics.drawable.Icon createWithData(byte[], int, int);
+    method @NonNull public static android.graphics.drawable.Icon createWithFilePath(String);
+    method @NonNull public static android.graphics.drawable.Icon createWithResource(android.content.Context, @DrawableRes int);
+    method @NonNull public static android.graphics.drawable.Icon createWithResource(String, @DrawableRes int);
     method public int describeContents();
     method @DrawableRes public int getResId();
     method @NonNull public String getResPackage();
     method public int getType();
     method @NonNull public android.net.Uri getUri();
-    method public android.graphics.drawable.Drawable loadDrawable(android.content.Context);
-    method public void loadDrawableAsync(android.content.Context, android.os.Message);
-    method public void loadDrawableAsync(android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler);
-    method public android.graphics.drawable.Icon setTint(@ColorInt int);
+    method @Nullable public android.graphics.drawable.Drawable loadDrawable(android.content.Context);
+    method public void loadDrawableAsync(@NonNull android.content.Context, @NonNull android.os.Message);
+    method public void loadDrawableAsync(@NonNull android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler);
+    method @NonNull public android.graphics.drawable.Icon setTint(@ColorInt int);
     method @NonNull public android.graphics.drawable.Icon setTintBlendMode(@NonNull android.graphics.BlendMode);
-    method public android.graphics.drawable.Icon setTintList(android.content.res.ColorStateList);
+    method @NonNull public android.graphics.drawable.Icon setTintList(android.content.res.ColorStateList);
     method @NonNull public android.graphics.drawable.Icon setTintMode(@NonNull android.graphics.PorterDuff.Mode);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.graphics.drawable.Icon> CREATOR;
@@ -16867,13 +16818,18 @@
     field public static final int REPORTING_MODE_ON_CHANGE = 1; // 0x1
     field public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3; // 0x3
     field public static final String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+    field public static final String STRING_TYPE_ACCELEROMETER_LIMITED_AXES = "android.sensor.accelerometer_limited_axes";
+    field public static final String STRING_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = "android.sensor.accelerometer_limited_axes_uncalibrated";
     field public static final String STRING_TYPE_ACCELEROMETER_UNCALIBRATED = "android.sensor.accelerometer_uncalibrated";
     field public static final String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
     field public static final String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
     field public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
     field public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity";
     field public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+    field public static final String STRING_TYPE_GYROSCOPE_LIMITED_AXES = "android.sensor.gyroscope_limited_axes";
+    field public static final String STRING_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = "android.sensor.gyroscope_limited_axes_uncalibrated";
     field public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+    field public static final String STRING_TYPE_HEADING = "android.sensor.heading";
     field public static final String STRING_TYPE_HEAD_TRACKER = "android.sensor.head_tracker";
     field public static final String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
     field public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
@@ -16896,6 +16852,8 @@
     field public static final String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
     field @Deprecated public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
+    field public static final int TYPE_ACCELEROMETER_LIMITED_AXES = 38; // 0x26
+    field public static final int TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40; // 0x28
     field public static final int TYPE_ACCELEROMETER_UNCALIBRATED = 35; // 0x23
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -16904,7 +16862,10 @@
     field public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20; // 0x14
     field public static final int TYPE_GRAVITY = 9; // 0x9
     field public static final int TYPE_GYROSCOPE = 4; // 0x4
+    field public static final int TYPE_GYROSCOPE_LIMITED_AXES = 39; // 0x27
+    field public static final int TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41; // 0x29
     field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+    field public static final int TYPE_HEADING = 42; // 0x2a
     field public static final int TYPE_HEAD_TRACKER = 37; // 0x25
     field public static final int TYPE_HEART_BEAT = 31; // 0x1f
     field public static final int TYPE_HEART_RATE = 21; // 0x15
@@ -17273,6 +17234,8 @@
     method @NonNull public java.util.List<android.hardware.camera2.CameraCharacteristics.Key<?>> getKeysNeedingPermission();
     method @NonNull public java.util.Set<java.lang.String> getPhysicalCameraIds();
     method @Nullable public android.hardware.camera2.params.RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(int);
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> AUTOMOTIVE_LENS_FACING;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> AUTOMOTIVE_LOCATION;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_MODES;
@@ -17334,12 +17297,14 @@
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SCALER_DEFAULT_SECURE_IMAGE_SIZE;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_STREAM_COMBINATIONS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS;
+    field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MultiResolutionStreamConfigurationMap> SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP;
     field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION;
@@ -17433,6 +17398,8 @@
   }
 
   public final class CameraExtensionCharacteristics {
+    method @NonNull public java.util.Set<android.hardware.camera2.CaptureRequest.Key> getAvailableCaptureRequestKeys(int);
+    method @NonNull public java.util.Set<android.hardware.camera2.CaptureResult.Key> getAvailableCaptureResultKeys(int);
     method @Nullable public android.util.Range<java.lang.Long> getEstimatedCaptureLatencyRangeMillis(int, @NonNull android.util.Size, int);
     method @NonNull public <T> java.util.List<android.util.Size> getExtensionSupportedSizes(int, @NonNull Class<T>);
     method @NonNull public java.util.List<android.util.Size> getExtensionSupportedSizes(int, int);
@@ -17457,6 +17424,7 @@
     ctor public CameraExtensionSession.ExtensionCaptureCallback();
     method public void onCaptureFailed(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest);
     method public void onCaptureProcessStarted(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest);
+    method public void onCaptureResultAvailable(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, @NonNull android.hardware.camera2.TotalCaptureResult);
     method public void onCaptureSequenceAborted(@NonNull android.hardware.camera2.CameraExtensionSession, int);
     method public void onCaptureSequenceCompleted(@NonNull android.hardware.camera2.CameraExtensionSession, int);
     method public void onCaptureStarted(@NonNull android.hardware.camera2.CameraExtensionSession, @NonNull android.hardware.camera2.CaptureRequest, long);
@@ -17506,6 +17474,32 @@
 
   public abstract class CameraMetadata<TKey> {
     method @NonNull public java.util.List<TKey> getKeys();
+    field public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_FRONT = 1; // 0x1
+    field public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_LEFT = 3; // 0x3
+    field public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER = 0; // 0x0
+    field public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_REAR = 2; // 0x2
+    field public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_RIGHT = 4; // 0x4
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER = 5; // 0x5
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_CENTER = 7; // 0x7
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_LEFT = 6; // 0x6
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_RIGHT = 8; // 0x8
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_CENTER = 10; // 0xa
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_LEFT = 9; // 0x9
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_RIGHT = 11; // 0xb
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_CENTER = 13; // 0xd
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_LEFT = 12; // 0xc
+    field public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_RIGHT = 14; // 0xe
+    field public static final int AUTOMOTIVE_LOCATION_EXTERIOR_FRONT = 2; // 0x2
+    field public static final int AUTOMOTIVE_LOCATION_EXTERIOR_LEFT = 4; // 0x4
+    field public static final int AUTOMOTIVE_LOCATION_EXTERIOR_OTHER = 1; // 0x1
+    field public static final int AUTOMOTIVE_LOCATION_EXTERIOR_REAR = 3; // 0x3
+    field public static final int AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT = 5; // 0x5
+    field public static final int AUTOMOTIVE_LOCATION_EXTRA_FRONT = 7; // 0x7
+    field public static final int AUTOMOTIVE_LOCATION_EXTRA_LEFT = 9; // 0x9
+    field public static final int AUTOMOTIVE_LOCATION_EXTRA_OTHER = 6; // 0x6
+    field public static final int AUTOMOTIVE_LOCATION_EXTRA_REAR = 8; // 0x8
+    field public static final int AUTOMOTIVE_LOCATION_EXTRA_RIGHT = 10; // 0xa
+    field public static final int AUTOMOTIVE_LOCATION_INTERIOR = 0; // 0x0
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
     field public static final int COLOR_CORRECTION_ABERRATION_MODE_OFF = 0; // 0x0
@@ -17640,6 +17634,7 @@
     field public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0; // 0x0
     field public static final int LENS_OPTICAL_STABILIZATION_MODE_OFF = 0; // 0x0
     field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1
+    field public static final int LENS_POSE_REFERENCE_AUTOMOTIVE = 3; // 0x3
     field public static final int LENS_POSE_REFERENCE_GYROSCOPE = 1; // 0x1
     field public static final int LENS_POSE_REFERENCE_PRIMARY_CAMERA = 0; // 0x0
     field public static final int LENS_POSE_REFERENCE_UNDEFINED = 2; // 0x2
@@ -17668,9 +17663,16 @@
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING = 17; // 0x11
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA = 13; // 0xd
+    field public static final int REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19; // 0x13
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA = 14; // 0xe
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR = 16; // 0x10
     field public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7; // 0x7
+    field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0; // 0x0
+    field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 1; // 0x1
+    field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 4; // 0x4
+    field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 2; // 0x2
+    field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 5; // 0x5
+    field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 3; // 0x3
     field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0
     field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1
     field public static final int SCALER_ROTATE_AND_CROP_180 = 2; // 0x2
@@ -18078,6 +18080,7 @@
     method public int get10BitFormat();
     method @NonNull public java.util.List<android.util.Size> getAvailableSizes();
     method public int getFormat();
+    method public int getStreamUseCase();
     method public boolean is10BitCapable();
     method public boolean isInput();
     method public boolean isMaximumSize();
@@ -18134,6 +18137,7 @@
     method public void enableSurfaceSharing();
     method public int getDynamicRangeProfile();
     method public int getMaxSharedSurfaceCount();
+    method public int getStreamUseCase();
     method @Nullable public android.view.Surface getSurface();
     method public int getSurfaceGroupId();
     method @NonNull public java.util.List<android.view.Surface> getSurfaces();
@@ -18141,6 +18145,7 @@
     method public void removeSurface(@NonNull android.view.Surface);
     method public void setDynamicRangeProfile(int);
     method public void setPhysicalCameraId(@Nullable String);
+    method public void setStreamUseCase(int);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
     field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
@@ -19676,10 +19681,13 @@
     method public android.media.AudioAttributes.Builder setUsage(int);
   }
 
-  public class AudioDescriptor {
+  public class AudioDescriptor implements android.os.Parcelable {
+    method public int describeContents();
     method @NonNull public byte[] getDescriptor();
     method public int getEncapsulationType();
     method public int getStandard();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioDescriptor> CREATOR;
     field public static final int STANDARD_EDID = 1; // 0x1
     field public static final int STANDARD_NONE = 0; // 0x0
   }
@@ -20195,14 +20203,17 @@
     method @NonNull public android.media.AudioPresentation.Builder setProgramId(int);
   }
 
-  public class AudioProfile {
+  public class AudioProfile implements android.os.Parcelable {
+    method public int describeContents();
     method @NonNull public int[] getChannelIndexMasks();
     method @NonNull public int[] getChannelMasks();
     method public int getEncapsulationType();
     method public int getFormat();
     method @NonNull public int[] getSampleRates();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int AUDIO_ENCAPSULATION_TYPE_IEC61937 = 1; // 0x1
     field public static final int AUDIO_ENCAPSULATION_TYPE_NONE = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioProfile> CREATOR;
   }
 
   public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {
@@ -26391,75 +26402,6 @@
     method @NonNull public android.net.Ikev2VpnProfile.Builder setProxy(@Nullable android.net.ProxyInfo);
   }
 
-  public final class IpSecAlgorithm implements android.os.Parcelable {
-    ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[]);
-    ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[], int);
-    method public int describeContents();
-    method @NonNull public byte[] getKey();
-    method @NonNull public String getName();
-    method @NonNull public static java.util.Set<java.lang.String> getSupportedAlgorithms();
-    method public int getTruncationLengthBits();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final String AUTH_AES_CMAC = "cmac(aes)";
-    field public static final String AUTH_AES_XCBC = "xcbc(aes)";
-    field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
-    field public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)";
-    field public static final String AUTH_HMAC_MD5 = "hmac(md5)";
-    field public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
-    field public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
-    field public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
-    field public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
-    field public static final String CRYPT_AES_CBC = "cbc(aes)";
-    field public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))";
-  }
-
-  public final class IpSecManager {
-    method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
-    method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
-    method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
-    method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
-    method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException;
-    method public void removeTransportModeTransforms(@NonNull java.net.DatagramSocket) throws java.io.IOException;
-    method public void removeTransportModeTransforms(@NonNull java.io.FileDescriptor) throws java.io.IOException;
-    field public static final int DIRECTION_IN = 0; // 0x0
-    field public static final int DIRECTION_OUT = 1; // 0x1
-  }
-
-  public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
-  }
-
-  public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
-    method public void close();
-    method public int getSpi();
-  }
-
-  public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
-    method public int getSpi();
-  }
-
-  public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
-    method public void close() throws java.io.IOException;
-    method public java.io.FileDescriptor getFileDescriptor();
-    method public int getPort();
-  }
-
-  public final class IpSecTransform implements java.lang.AutoCloseable {
-    method public void close();
-  }
-
-  public static class IpSecTransform.Builder {
-    ctor public IpSecTransform.Builder(@NonNull android.content.Context);
-    method @NonNull public android.net.IpSecTransform buildTransportModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
-    method @NonNull public android.net.IpSecTransform.Builder setAuthenticatedEncryption(@NonNull android.net.IpSecAlgorithm);
-    method @NonNull public android.net.IpSecTransform.Builder setAuthentication(@NonNull android.net.IpSecAlgorithm);
-    method @NonNull public android.net.IpSecTransform.Builder setEncryption(@NonNull android.net.IpSecAlgorithm);
-    method @NonNull public android.net.IpSecTransform.Builder setIpv4Encapsulation(@NonNull android.net.IpSecManager.UdpEncapsulationSocket, int);
-  }
-
   public class LocalServerSocket implements java.io.Closeable {
     ctor public LocalServerSocket(String) throws java.io.IOException;
     ctor public LocalServerSocket(java.io.FileDescriptor) throws java.io.IOException;
@@ -26586,50 +26528,6 @@
     method @NonNull public android.net.TelephonyNetworkSpecifier.Builder setSubscriptionId(int);
   }
 
-  public class TrafficStats {
-    ctor public TrafficStats();
-    method public static void clearThreadStatsTag();
-    method public static void clearThreadStatsUid();
-    method public static int getAndSetThreadStatsTag(int);
-    method public static long getMobileRxBytes();
-    method public static long getMobileRxPackets();
-    method public static long getMobileTxBytes();
-    method public static long getMobileTxPackets();
-    method public static long getRxBytes(@NonNull String);
-    method public static long getRxPackets(@NonNull String);
-    method public static int getThreadStatsTag();
-    method public static int getThreadStatsUid();
-    method public static long getTotalRxBytes();
-    method public static long getTotalRxPackets();
-    method public static long getTotalTxBytes();
-    method public static long getTotalTxPackets();
-    method public static long getTxBytes(@NonNull String);
-    method public static long getTxPackets(@NonNull String);
-    method public static long getUidRxBytes(int);
-    method public static long getUidRxPackets(int);
-    method @Deprecated public static long getUidTcpRxBytes(int);
-    method @Deprecated public static long getUidTcpRxSegments(int);
-    method @Deprecated public static long getUidTcpTxBytes(int);
-    method @Deprecated public static long getUidTcpTxSegments(int);
-    method public static long getUidTxBytes(int);
-    method public static long getUidTxPackets(int);
-    method @Deprecated public static long getUidUdpRxBytes(int);
-    method @Deprecated public static long getUidUdpRxPackets(int);
-    method @Deprecated public static long getUidUdpTxBytes(int);
-    method @Deprecated public static long getUidUdpTxPackets(int);
-    method public static void incrementOperationCount(int);
-    method public static void incrementOperationCount(int, int);
-    method public static void setThreadStatsTag(int);
-    method public static void setThreadStatsUid(int);
-    method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
-    method public static void tagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException;
-    method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
-    method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
-    method public static void untagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException;
-    method public static void untagSocket(java.net.Socket) throws java.net.SocketException;
-    field public static final int UNSUPPORTED = -1; // 0xffffffff
-  }
-
   public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
     method public abstract android.net.Uri.Builder buildUpon();
     method public int compareTo(android.net.Uri);
@@ -39436,6 +39334,7 @@
   public interface RecognitionListener {
     method public void onBeginningOfSpeech();
     method public void onBufferReceived(byte[]);
+    method public default void onEndOfSegmentedSession();
     method public void onEndOfSpeech();
     method public void onError(int);
     method public void onEvent(int, android.os.Bundle);
@@ -39443,6 +39342,7 @@
     method public void onReadyForSpeech(android.os.Bundle);
     method public void onResults(android.os.Bundle);
     method public void onRmsChanged(float);
+    method public default void onSegmentResults(@NonNull android.os.Bundle);
   }
 
   public abstract class RecognitionService extends android.app.Service {
@@ -39460,6 +39360,7 @@
   public class RecognitionService.Callback {
     method public void beginningOfSpeech() throws android.os.RemoteException;
     method public void bufferReceived(byte[]) throws android.os.RemoteException;
+    method public void endOfSegmentedSession() throws android.os.RemoteException;
     method public void endOfSpeech() throws android.os.RemoteException;
     method public void error(int) throws android.os.RemoteException;
     method @NonNull public android.content.AttributionSource getCallingAttributionSource();
@@ -39468,6 +39369,7 @@
     method public void readyForSpeech(android.os.Bundle) throws android.os.RemoteException;
     method public void results(android.os.Bundle) throws android.os.RemoteException;
     method public void rmsChanged(float) throws android.os.RemoteException;
+    method public void segmentResults(@NonNull android.os.Bundle) throws android.os.RemoteException;
   }
 
   public static class RecognitionService.SupportCallback {
@@ -39523,6 +39425,7 @@
     field public static final String EXTRA_RESULTS_PENDINGINTENT = "android.speech.extra.RESULTS_PENDINGINTENT";
     field public static final String EXTRA_RESULTS_PENDINGINTENT_BUNDLE = "android.speech.extra.RESULTS_PENDINGINTENT_BUNDLE";
     field public static final String EXTRA_SECURE = "android.speech.extras.EXTRA_SECURE";
+    field public static final String EXTRA_SEGMENT_SESSION = "android.speech.extra.SEGMENT_SESSION";
     field public static final String EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS";
     field public static final String EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS";
     field public static final String EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extras.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS";
@@ -43009,6 +42912,7 @@
     field public static final int ENCODING_16BIT = 3; // 0x3
     field public static final int ENCODING_7BIT = 1; // 0x1
     field public static final int ENCODING_8BIT = 2; // 0x2
+    field public static final int ENCODING_KSC5601 = 4; // 0x4
     field public static final int ENCODING_UNKNOWN = 0; // 0x0
     field public static final String FORMAT_3GPP = "3gpp";
     field public static final String FORMAT_3GPP2 = "3gpp2";
@@ -43103,7 +43007,8 @@
     method public void setSubscriptionOverrideCongested(int, boolean, @NonNull int[], long);
     method public void setSubscriptionOverrideUnmetered(int, boolean, long);
     method public void setSubscriptionOverrideUnmetered(int, boolean, @NonNull int[], long);
-    method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>);
+    method @Deprecated public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>);
+    method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>, long);
     method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, @NonNull android.app.PendingIntent);
     field public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED";
     field public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED";
@@ -43286,6 +43191,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
     method public int getActiveModemCount();
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public long getAllowedNetworkTypesForReason(int);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCallComposerStatus();
     method @Deprecated @RequiresPermission(value=android.Manifest.permission.READ_PHONE_STATE, conditional=true) public int getCallState();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getCallStateForSubscription();
@@ -43346,6 +43252,7 @@
     method public int getSubscriptionId();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubscriptionId(@NonNull android.telecom.PhoneAccountHandle);
     method public int getSupportedModemCount();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public long getSupportedRadioAccessFamily();
     method @Nullable public String getTypeAllocationCode();
     method @Nullable public String getTypeAllocationCode(int);
     method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telephony.UiccCardInfo> getUiccCardsInfo();
@@ -43391,6 +43298,7 @@
     method public String sendEnvelopeWithStatus(String);
     method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
     method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAllowedNetworkTypesForReason(int, long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallComposerStatus(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean);
@@ -43427,6 +43335,8 @@
     field public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
     field public static final String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";
     field public static final String ACTION_SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_SPECIFIC_CARRIER_IDENTITY_CHANGED";
+    field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2
+    field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0
     field public static final int APPTYPE_CSIM = 4; // 0x4
     field public static final int APPTYPE_ISIM = 5; // 0x5
     field public static final int APPTYPE_RUIM = 3; // 0x3
@@ -43501,6 +43411,26 @@
     field public static final int NETWORK_SELECTION_MODE_MANUAL = 2; // 0x2
     field public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0; // 0x0
     field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
+    field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L
+    field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L
+    field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L
+    field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L
+    field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L
+    field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L
+    field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L
+    field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L
+    field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L
+    field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L
+    field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L
+    field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L
+    field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L
+    field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L
+    field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L
+    field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L
+    field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L
+    field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L
+    field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L
+    field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L
     field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
     field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
     field public static final int NETWORK_TYPE_EHRPD = 14; // 0xe
@@ -47613,16 +47543,16 @@
   }
 
   public abstract class ActionProvider {
-    ctor public ActionProvider(android.content.Context);
+    ctor public ActionProvider(@NonNull android.content.Context);
     method public boolean hasSubMenu();
     method public boolean isVisible();
-    method @Deprecated public abstract android.view.View onCreateActionView();
-    method public android.view.View onCreateActionView(android.view.MenuItem);
+    method @Deprecated @NonNull public abstract android.view.View onCreateActionView();
+    method @NonNull public android.view.View onCreateActionView(@NonNull android.view.MenuItem);
     method public boolean onPerformDefaultAction();
-    method public void onPrepareSubMenu(android.view.SubMenu);
+    method public void onPrepareSubMenu(@NonNull android.view.SubMenu);
     method public boolean overridesItemVisibility();
     method public void refreshVisibility();
-    method public void setVisibilityListener(android.view.ActionProvider.VisibilityListener);
+    method public void setVisibilityListener(@Nullable android.view.ActionProvider.VisibilityListener);
   }
 
   public static interface ActionProvider.VisibilityListener {
@@ -47892,60 +47822,60 @@
   }
 
   public class GestureDetector {
-    ctor @Deprecated public GestureDetector(android.view.GestureDetector.OnGestureListener, android.os.Handler);
-    ctor @Deprecated public GestureDetector(android.view.GestureDetector.OnGestureListener);
-    ctor public GestureDetector(@UiContext android.content.Context, android.view.GestureDetector.OnGestureListener);
-    ctor public GestureDetector(@UiContext android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler);
-    ctor public GestureDetector(@UiContext android.content.Context, android.view.GestureDetector.OnGestureListener, android.os.Handler, boolean);
+    ctor @Deprecated public GestureDetector(@NonNull android.view.GestureDetector.OnGestureListener, @Nullable android.os.Handler);
+    ctor @Deprecated public GestureDetector(@NonNull android.view.GestureDetector.OnGestureListener);
+    ctor public GestureDetector(@Nullable @UiContext android.content.Context, @NonNull android.view.GestureDetector.OnGestureListener);
+    ctor public GestureDetector(@Nullable @UiContext android.content.Context, @NonNull android.view.GestureDetector.OnGestureListener, @Nullable android.os.Handler);
+    ctor public GestureDetector(@Nullable @UiContext android.content.Context, @NonNull android.view.GestureDetector.OnGestureListener, @Nullable android.os.Handler, boolean);
     method public boolean isLongpressEnabled();
-    method public boolean onGenericMotionEvent(android.view.MotionEvent);
-    method public boolean onTouchEvent(android.view.MotionEvent);
-    method public void setContextClickListener(android.view.GestureDetector.OnContextClickListener);
+    method public boolean onGenericMotionEvent(@NonNull android.view.MotionEvent);
+    method public boolean onTouchEvent(@NonNull android.view.MotionEvent);
+    method public void setContextClickListener(@Nullable android.view.GestureDetector.OnContextClickListener);
     method public void setIsLongpressEnabled(boolean);
-    method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener);
+    method public void setOnDoubleTapListener(@Nullable android.view.GestureDetector.OnDoubleTapListener);
   }
 
   public static interface GestureDetector.OnContextClickListener {
-    method public boolean onContextClick(android.view.MotionEvent);
+    method public boolean onContextClick(@NonNull android.view.MotionEvent);
   }
 
   public static interface GestureDetector.OnDoubleTapListener {
-    method public boolean onDoubleTap(android.view.MotionEvent);
-    method public boolean onDoubleTapEvent(android.view.MotionEvent);
-    method public boolean onSingleTapConfirmed(android.view.MotionEvent);
+    method public boolean onDoubleTap(@NonNull android.view.MotionEvent);
+    method public boolean onDoubleTapEvent(@NonNull android.view.MotionEvent);
+    method public boolean onSingleTapConfirmed(@NonNull android.view.MotionEvent);
   }
 
   public static interface GestureDetector.OnGestureListener {
-    method public boolean onDown(android.view.MotionEvent);
-    method public boolean onFling(android.view.MotionEvent, android.view.MotionEvent, float, float);
-    method public void onLongPress(android.view.MotionEvent);
-    method public boolean onScroll(android.view.MotionEvent, android.view.MotionEvent, float, float);
-    method public void onShowPress(android.view.MotionEvent);
-    method public boolean onSingleTapUp(android.view.MotionEvent);
+    method public boolean onDown(@NonNull android.view.MotionEvent);
+    method public boolean onFling(@NonNull android.view.MotionEvent, @NonNull android.view.MotionEvent, float, float);
+    method public void onLongPress(@NonNull android.view.MotionEvent);
+    method public boolean onScroll(@NonNull android.view.MotionEvent, @NonNull android.view.MotionEvent, float, float);
+    method public void onShowPress(@NonNull android.view.MotionEvent);
+    method public boolean onSingleTapUp(@NonNull android.view.MotionEvent);
   }
 
   public static class GestureDetector.SimpleOnGestureListener implements android.view.GestureDetector.OnContextClickListener android.view.GestureDetector.OnDoubleTapListener android.view.GestureDetector.OnGestureListener {
     ctor public GestureDetector.SimpleOnGestureListener();
-    method public boolean onContextClick(android.view.MotionEvent);
-    method public boolean onDoubleTap(android.view.MotionEvent);
-    method public boolean onDoubleTapEvent(android.view.MotionEvent);
-    method public boolean onDown(android.view.MotionEvent);
-    method public boolean onFling(android.view.MotionEvent, android.view.MotionEvent, float, float);
-    method public void onLongPress(android.view.MotionEvent);
-    method public boolean onScroll(android.view.MotionEvent, android.view.MotionEvent, float, float);
-    method public void onShowPress(android.view.MotionEvent);
-    method public boolean onSingleTapConfirmed(android.view.MotionEvent);
-    method public boolean onSingleTapUp(android.view.MotionEvent);
+    method public boolean onContextClick(@NonNull android.view.MotionEvent);
+    method public boolean onDoubleTap(@NonNull android.view.MotionEvent);
+    method public boolean onDoubleTapEvent(@NonNull android.view.MotionEvent);
+    method public boolean onDown(@NonNull android.view.MotionEvent);
+    method public boolean onFling(@NonNull android.view.MotionEvent, @NonNull android.view.MotionEvent, float, float);
+    method public void onLongPress(@NonNull android.view.MotionEvent);
+    method public boolean onScroll(@NonNull android.view.MotionEvent, @NonNull android.view.MotionEvent, float, float);
+    method public void onShowPress(@NonNull android.view.MotionEvent);
+    method public boolean onSingleTapConfirmed(@NonNull android.view.MotionEvent);
+    method public boolean onSingleTapUp(@NonNull android.view.MotionEvent);
   }
 
   public class Gravity {
     ctor public Gravity();
     method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect);
-    method public static void apply(int, int, int, android.graphics.Rect, android.graphics.Rect, int);
-    method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect);
-    method public static void apply(int, int, int, android.graphics.Rect, int, int, android.graphics.Rect, int);
-    method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect);
-    method public static void applyDisplay(int, android.graphics.Rect, android.graphics.Rect, int);
+    method public static void apply(int, int, int, @NonNull android.graphics.Rect, @NonNull android.graphics.Rect, int);
+    method public static void apply(int, int, int, @NonNull android.graphics.Rect, int, int, @NonNull android.graphics.Rect);
+    method public static void apply(int, int, int, @NonNull android.graphics.Rect, int, int, @NonNull android.graphics.Rect, int);
+    method public static void applyDisplay(int, @NonNull android.graphics.Rect, @NonNull android.graphics.Rect);
+    method public static void applyDisplay(int, @NonNull android.graphics.Rect, @NonNull android.graphics.Rect, int);
     method public static int getAbsoluteGravity(int, int);
     method public static boolean isHorizontal(int);
     method public static boolean isVertical(int);
@@ -48677,60 +48607,60 @@
   public interface MenuItem {
     method public boolean collapseActionView();
     method public boolean expandActionView();
-    method public android.view.ActionProvider getActionProvider();
-    method public android.view.View getActionView();
+    method @Nullable public android.view.ActionProvider getActionProvider();
+    method @Nullable public android.view.View getActionView();
     method public default int getAlphabeticModifiers();
     method public char getAlphabeticShortcut();
-    method public default CharSequence getContentDescription();
+    method @Nullable public default CharSequence getContentDescription();
     method public int getGroupId();
-    method public android.graphics.drawable.Drawable getIcon();
+    method @Nullable public android.graphics.drawable.Drawable getIcon();
     method @Nullable public default android.graphics.BlendMode getIconTintBlendMode();
     method @Nullable public default android.content.res.ColorStateList getIconTintList();
     method @Nullable public default android.graphics.PorterDuff.Mode getIconTintMode();
-    method public android.content.Intent getIntent();
+    method @Nullable public android.content.Intent getIntent();
     method public int getItemId();
-    method public android.view.ContextMenu.ContextMenuInfo getMenuInfo();
+    method @Nullable public android.view.ContextMenu.ContextMenuInfo getMenuInfo();
     method public default int getNumericModifiers();
     method public char getNumericShortcut();
     method public int getOrder();
-    method public android.view.SubMenu getSubMenu();
-    method public CharSequence getTitle();
-    method public CharSequence getTitleCondensed();
-    method public default CharSequence getTooltipText();
+    method @Nullable public android.view.SubMenu getSubMenu();
+    method @Nullable public CharSequence getTitle();
+    method @Nullable public CharSequence getTitleCondensed();
+    method @Nullable public default CharSequence getTooltipText();
     method public boolean hasSubMenu();
     method public boolean isActionViewExpanded();
     method public boolean isCheckable();
     method public boolean isChecked();
     method public boolean isEnabled();
     method public boolean isVisible();
-    method public android.view.MenuItem setActionProvider(android.view.ActionProvider);
-    method public android.view.MenuItem setActionView(android.view.View);
-    method public android.view.MenuItem setActionView(@LayoutRes int);
-    method public android.view.MenuItem setAlphabeticShortcut(char);
-    method public default android.view.MenuItem setAlphabeticShortcut(char, int);
-    method public android.view.MenuItem setCheckable(boolean);
-    method public android.view.MenuItem setChecked(boolean);
-    method public default android.view.MenuItem setContentDescription(CharSequence);
-    method public android.view.MenuItem setEnabled(boolean);
-    method public android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
-    method public android.view.MenuItem setIcon(@DrawableRes int);
+    method @NonNull public android.view.MenuItem setActionProvider(@Nullable android.view.ActionProvider);
+    method @NonNull public android.view.MenuItem setActionView(@Nullable android.view.View);
+    method @NonNull public android.view.MenuItem setActionView(@LayoutRes int);
+    method @NonNull public android.view.MenuItem setAlphabeticShortcut(char);
+    method @NonNull public default android.view.MenuItem setAlphabeticShortcut(char, int);
+    method @NonNull public android.view.MenuItem setCheckable(boolean);
+    method @NonNull public android.view.MenuItem setChecked(boolean);
+    method @NonNull public default android.view.MenuItem setContentDescription(@Nullable CharSequence);
+    method @NonNull public android.view.MenuItem setEnabled(boolean);
+    method @NonNull public android.view.MenuItem setIcon(@Nullable android.graphics.drawable.Drawable);
+    method @NonNull public android.view.MenuItem setIcon(@DrawableRes int);
     method @NonNull public default android.view.MenuItem setIconTintBlendMode(@Nullable android.graphics.BlendMode);
-    method public default android.view.MenuItem setIconTintList(@Nullable android.content.res.ColorStateList);
+    method @NonNull public default android.view.MenuItem setIconTintList(@Nullable android.content.res.ColorStateList);
     method @NonNull public default android.view.MenuItem setIconTintMode(@Nullable android.graphics.PorterDuff.Mode);
-    method public android.view.MenuItem setIntent(android.content.Intent);
-    method public android.view.MenuItem setNumericShortcut(char);
-    method public default android.view.MenuItem setNumericShortcut(char, int);
-    method public android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
-    method public android.view.MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener);
-    method public android.view.MenuItem setShortcut(char, char);
-    method public default android.view.MenuItem setShortcut(char, char, int, int);
+    method @NonNull public android.view.MenuItem setIntent(@Nullable android.content.Intent);
+    method @NonNull public android.view.MenuItem setNumericShortcut(char);
+    method @NonNull public default android.view.MenuItem setNumericShortcut(char, int);
+    method @NonNull public android.view.MenuItem setOnActionExpandListener(@Nullable android.view.MenuItem.OnActionExpandListener);
+    method @NonNull public android.view.MenuItem setOnMenuItemClickListener(@Nullable android.view.MenuItem.OnMenuItemClickListener);
+    method @NonNull public android.view.MenuItem setShortcut(char, char);
+    method @NonNull public default android.view.MenuItem setShortcut(char, char, int, int);
     method public void setShowAsAction(int);
-    method public android.view.MenuItem setShowAsActionFlags(int);
-    method public android.view.MenuItem setTitle(CharSequence);
-    method public android.view.MenuItem setTitle(@StringRes int);
-    method public android.view.MenuItem setTitleCondensed(CharSequence);
-    method public default android.view.MenuItem setTooltipText(CharSequence);
-    method public android.view.MenuItem setVisible(boolean);
+    method @NonNull public android.view.MenuItem setShowAsActionFlags(int);
+    method @NonNull public android.view.MenuItem setTitle(@Nullable CharSequence);
+    method @NonNull public android.view.MenuItem setTitle(@StringRes int);
+    method @NonNull public android.view.MenuItem setTitleCondensed(@Nullable CharSequence);
+    method @NonNull public default android.view.MenuItem setTooltipText(@Nullable CharSequence);
+    method @NonNull public android.view.MenuItem setVisible(boolean);
     field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
     field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
     field public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
@@ -48739,12 +48669,12 @@
   }
 
   public static interface MenuItem.OnActionExpandListener {
-    method public boolean onMenuItemActionCollapse(android.view.MenuItem);
-    method public boolean onMenuItemActionExpand(android.view.MenuItem);
+    method public boolean onMenuItemActionCollapse(@NonNull android.view.MenuItem);
+    method public boolean onMenuItemActionExpand(@NonNull android.view.MenuItem);
   }
 
   public static interface MenuItem.OnMenuItemClickListener {
-    method public boolean onMenuItemClick(android.view.MenuItem);
+    method public boolean onMenuItemClick(@NonNull android.view.MenuItem);
   }
 
   public final class MotionEvent extends android.view.InputEvent implements android.os.Parcelable {
@@ -48963,16 +48893,15 @@
     method public default void onBackInvoked();
   }
 
-  public abstract class OnBackInvokedDispatcher {
-    ctor public OnBackInvokedDispatcher();
-    method public abstract void registerOnBackInvokedCallback(@NonNull android.view.OnBackInvokedCallback, int);
-    method public abstract void unregisterOnBackInvokedCallback(@NonNull android.view.OnBackInvokedCallback);
+  public interface OnBackInvokedDispatcher {
+    method public void registerOnBackInvokedCallback(@NonNull android.view.OnBackInvokedCallback, @IntRange(from=0) int);
+    method public void unregisterOnBackInvokedCallback(@NonNull android.view.OnBackInvokedCallback);
     field public static final int PRIORITY_DEFAULT = 0; // 0x0
     field public static final int PRIORITY_OVERLAY = 1000000; // 0xf4240
   }
 
   public interface OnBackInvokedDispatcherOwner {
-    method @Nullable public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
+    method @NonNull public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
   }
 
   public interface OnReceiveContentListener {
@@ -49020,10 +48949,10 @@
   }
 
   public final class PointerIcon implements android.os.Parcelable {
-    method public static android.view.PointerIcon create(@NonNull android.graphics.Bitmap, float, float);
+    method @NonNull public static android.view.PointerIcon create(@NonNull android.graphics.Bitmap, float, float);
     method public int describeContents();
-    method public static android.view.PointerIcon getSystemIcon(@NonNull android.content.Context, int);
-    method public static android.view.PointerIcon load(@NonNull android.content.res.Resources, @XmlRes int);
+    method @NonNull public static android.view.PointerIcon getSystemIcon(@NonNull android.content.Context, int);
+    method @NonNull public static android.view.PointerIcon load(@NonNull android.content.res.Resources, @XmlRes int);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.PointerIcon> CREATOR;
     field public static final int TYPE_ALIAS = 1010; // 0x3f2
@@ -49066,8 +48995,8 @@
   }
 
   public class ScaleGestureDetector {
-    ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener);
-    ctor public ScaleGestureDetector(android.content.Context, android.view.ScaleGestureDetector.OnScaleGestureListener, android.os.Handler);
+    ctor public ScaleGestureDetector(@NonNull android.content.Context, @NonNull android.view.ScaleGestureDetector.OnScaleGestureListener);
+    ctor public ScaleGestureDetector(@NonNull android.content.Context, @NonNull android.view.ScaleGestureDetector.OnScaleGestureListener, @Nullable android.os.Handler);
     method public float getCurrentSpan();
     method public float getCurrentSpanX();
     method public float getCurrentSpanY();
@@ -49082,22 +49011,22 @@
     method public boolean isInProgress();
     method public boolean isQuickScaleEnabled();
     method public boolean isStylusScaleEnabled();
-    method public boolean onTouchEvent(android.view.MotionEvent);
+    method public boolean onTouchEvent(@NonNull android.view.MotionEvent);
     method public void setQuickScaleEnabled(boolean);
     method public void setStylusScaleEnabled(boolean);
   }
 
   public static interface ScaleGestureDetector.OnScaleGestureListener {
-    method public boolean onScale(android.view.ScaleGestureDetector);
-    method public boolean onScaleBegin(android.view.ScaleGestureDetector);
-    method public void onScaleEnd(android.view.ScaleGestureDetector);
+    method public boolean onScale(@NonNull android.view.ScaleGestureDetector);
+    method public boolean onScaleBegin(@NonNull android.view.ScaleGestureDetector);
+    method public void onScaleEnd(@NonNull android.view.ScaleGestureDetector);
   }
 
   public static class ScaleGestureDetector.SimpleOnScaleGestureListener implements android.view.ScaleGestureDetector.OnScaleGestureListener {
     ctor public ScaleGestureDetector.SimpleOnScaleGestureListener();
-    method public boolean onScale(android.view.ScaleGestureDetector);
-    method public boolean onScaleBegin(android.view.ScaleGestureDetector);
-    method public void onScaleEnd(android.view.ScaleGestureDetector);
+    method public boolean onScale(@NonNull android.view.ScaleGestureDetector);
+    method public boolean onScaleBegin(@NonNull android.view.ScaleGestureDetector);
+    method public void onScaleEnd(@NonNull android.view.ScaleGestureDetector);
   }
 
   @UiThread public interface ScrollCaptureCallback {
@@ -49215,7 +49144,7 @@
 
   public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable {
     ctor public SurfaceControl.Transaction();
-    method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.TransactionCommittedListener);
+    method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener);
     method public void apply();
     method public void close();
     method public int describeContents();
@@ -49239,6 +49168,10 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.view.SurfaceControl.Transaction> CREATOR;
   }
 
+  public static interface SurfaceControl.TransactionCommittedListener {
+    method public void onTransactionCommitted();
+  }
+
   public class SurfaceControlViewHost {
     ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder);
     method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage();
@@ -49351,10 +49284,6 @@
     field public static final int TO_RIGHT = 8; // 0x8
   }
 
-  public interface TransactionCommittedListener {
-    method public void onTransactionCommitted();
-  }
-
   public final class VelocityTracker {
     method public void addMovement(android.view.MotionEvent);
     method public void clear();
@@ -49400,7 +49329,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.view.VerifiedMotionEvent> CREATOR;
   }
 
-  @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback android.view.OnBackInvokedDispatcherOwner {
+  @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
     ctor public View(android.content.Context);
     ctor public View(android.content.Context, @Nullable android.util.AttributeSet);
     ctor public View(android.content.Context, @Nullable android.util.AttributeSet, int);
@@ -49468,7 +49397,7 @@
     method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
     method public boolean dispatchNestedFling(float, float, boolean);
     method public boolean dispatchNestedPreFling(float, float);
-    method public boolean dispatchNestedPrePerformAccessibilityAction(int, android.os.Bundle);
+    method public boolean dispatchNestedPrePerformAccessibilityAction(int, @Nullable android.os.Bundle);
     method public boolean dispatchNestedPreScroll(int, int, @Nullable @Size(2) int[], @Nullable @Size(2) int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, @Nullable @Size(2) int[]);
     method public void dispatchPointerCaptureChanged(boolean);
@@ -49604,7 +49533,6 @@
     method @IdRes public int getNextFocusLeftId();
     method @IdRes public int getNextFocusRightId();
     method @IdRes public int getNextFocusUpId();
-    method @Nullable public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
     method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
     method @ColorInt public int getOutlineAmbientShadowColor();
     method public android.view.ViewOutlineProvider getOutlineProvider();
@@ -49830,7 +49758,7 @@
     method @Deprecated public void onWindowSystemUiVisibilityChanged(int);
     method protected void onWindowVisibilityChanged(int);
     method protected boolean overScrollBy(int, int, int, int, int, int, int, int, boolean);
-    method public boolean performAccessibilityAction(int, android.os.Bundle);
+    method public boolean performAccessibilityAction(int, @Nullable android.os.Bundle);
     method public boolean performClick();
     method public boolean performContextClick(float, float);
     method public boolean performContextClick();
@@ -50241,15 +50169,15 @@
   public static class View.AccessibilityDelegate {
     ctor public View.AccessibilityDelegate();
     method public void addExtraDataToAccessibilityNodeInfo(@NonNull android.view.View, @NonNull android.view.accessibility.AccessibilityNodeInfo, @NonNull String, @Nullable android.os.Bundle);
-    method public boolean dispatchPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
-    method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(android.view.View);
-    method public void onInitializeAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
-    method public void onInitializeAccessibilityNodeInfo(android.view.View, android.view.accessibility.AccessibilityNodeInfo);
-    method public void onPopulateAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
-    method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup, android.view.View, android.view.accessibility.AccessibilityEvent);
-    method public boolean performAccessibilityAction(android.view.View, int, android.os.Bundle);
-    method public void sendAccessibilityEvent(android.view.View, int);
-    method public void sendAccessibilityEventUnchecked(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean dispatchPopulateAccessibilityEvent(@NonNull android.view.View, @NonNull android.view.accessibility.AccessibilityEvent);
+    method @Nullable public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider(@NonNull android.view.View);
+    method public void onInitializeAccessibilityEvent(@NonNull android.view.View, @NonNull android.view.accessibility.AccessibilityEvent);
+    method public void onInitializeAccessibilityNodeInfo(@NonNull android.view.View, @NonNull android.view.accessibility.AccessibilityNodeInfo);
+    method public void onPopulateAccessibilityEvent(@NonNull android.view.View, @NonNull android.view.accessibility.AccessibilityEvent);
+    method public boolean onRequestSendAccessibilityEvent(@NonNull android.view.ViewGroup, @NonNull android.view.View, @NonNull android.view.accessibility.AccessibilityEvent);
+    method public boolean performAccessibilityAction(@NonNull android.view.View, int, @Nullable android.os.Bundle);
+    method public void sendAccessibilityEvent(@NonNull android.view.View, int);
+    method public void sendAccessibilityEventUnchecked(@NonNull android.view.View, @NonNull android.view.accessibility.AccessibilityEvent);
   }
 
   public static class View.BaseSavedState extends android.view.AbsSavedState {
@@ -50279,12 +50207,12 @@
   }
 
   public static interface View.OnApplyWindowInsetsListener {
-    method public android.view.WindowInsets onApplyWindowInsets(android.view.View, android.view.WindowInsets);
+    method @NonNull public android.view.WindowInsets onApplyWindowInsets(@NonNull android.view.View, @NonNull android.view.WindowInsets);
   }
 
   public static interface View.OnAttachStateChangeListener {
-    method public void onViewAttachedToWindow(android.view.View);
-    method public void onViewDetachedFromWindow(android.view.View);
+    method public void onViewAttachedToWindow(@NonNull android.view.View);
+    method public void onViewDetachedFromWindow(@NonNull android.view.View);
   }
 
   public static interface View.OnCapturedPointerListener {
@@ -50353,7 +50281,7 @@
 
   public class ViewConfiguration {
     ctor @Deprecated public ViewConfiguration();
-    method public static android.view.ViewConfiguration get(@UiContext android.content.Context);
+    method public static android.view.ViewConfiguration get(@NonNull @UiContext android.content.Context);
     method @Deprecated @FloatRange(from=1.0) public static float getAmbiguousGestureMultiplier();
     method public static long getDefaultActionModeHideDuration();
     method public static int getDoubleTapTimeout();
@@ -50672,8 +50600,8 @@
     method public boolean canResolveLayoutDirection();
     method public boolean canResolveTextAlignment();
     method public boolean canResolveTextDirection();
-    method public void childDrawableStateChanged(android.view.View);
-    method public void childHasTransientStateChanged(android.view.View, boolean);
+    method public void childDrawableStateChanged(@NonNull android.view.View);
+    method public void childHasTransientStateChanged(@NonNull android.view.View, boolean);
     method public void clearChildFocus(android.view.View);
     method public void createContextMenu(android.view.ContextMenu);
     method public android.view.View focusSearch(android.view.View, int);
@@ -50691,23 +50619,23 @@
     method public boolean isTextAlignmentResolved();
     method public boolean isTextDirectionResolved();
     method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
-    method public void notifySubtreeAccessibilityStateChanged(android.view.View, @NonNull android.view.View, int);
+    method public void notifySubtreeAccessibilityStateChanged(@NonNull android.view.View, @NonNull android.view.View, int);
     method public default void onDescendantInvalidated(@NonNull android.view.View, @NonNull android.view.View);
-    method public boolean onNestedFling(android.view.View, float, float, boolean);
-    method public boolean onNestedPreFling(android.view.View, float, float);
-    method public boolean onNestedPrePerformAccessibilityAction(android.view.View, int, android.os.Bundle);
-    method public void onNestedPreScroll(android.view.View, int, int, int[]);
-    method public void onNestedScroll(android.view.View, int, int, int, int);
-    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
-    method public boolean onStartNestedScroll(android.view.View, android.view.View, int);
-    method public void onStopNestedScroll(android.view.View);
+    method public boolean onNestedFling(@NonNull android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(@NonNull android.view.View, float, float);
+    method public boolean onNestedPrePerformAccessibilityAction(@NonNull android.view.View, int, @Nullable android.os.Bundle);
+    method public void onNestedPreScroll(@NonNull android.view.View, int, int, @NonNull int[]);
+    method public void onNestedScroll(@NonNull android.view.View, int, int, int, int);
+    method public void onNestedScrollAccepted(@NonNull android.view.View, @NonNull android.view.View, int);
+    method public boolean onStartNestedScroll(@NonNull android.view.View, @NonNull android.view.View, int);
+    method public void onStopNestedScroll(@NonNull android.view.View);
     method public void recomputeViewAttributes(android.view.View);
     method public void requestChildFocus(android.view.View, android.view.View);
-    method public boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
+    method public boolean requestChildRectangleOnScreen(@NonNull android.view.View, android.graphics.Rect, boolean);
     method public void requestDisallowInterceptTouchEvent(boolean);
     method public void requestFitSystemWindows();
     method public void requestLayout();
-    method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
+    method public boolean requestSendAccessibilityEvent(@NonNull android.view.View, android.view.accessibility.AccessibilityEvent);
     method public void requestTransparentRegion(android.view.View);
     method public boolean showContextMenuForChild(android.view.View);
     method public boolean showContextMenuForChild(android.view.View, float, float);
@@ -50716,43 +50644,43 @@
   }
 
   public class ViewPropertyAnimator {
-    method public android.view.ViewPropertyAnimator alpha(@FloatRange(from=0.0f, to=1.0f) float);
-    method public android.view.ViewPropertyAnimator alphaBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator alpha(@FloatRange(from=0.0f, to=1.0f) float);
+    method @NonNull public android.view.ViewPropertyAnimator alphaBy(float);
     method public void cancel();
     method public long getDuration();
-    method public android.animation.TimeInterpolator getInterpolator();
+    method @Nullable public android.animation.TimeInterpolator getInterpolator();
     method public long getStartDelay();
-    method public android.view.ViewPropertyAnimator rotation(float);
-    method public android.view.ViewPropertyAnimator rotationBy(float);
-    method public android.view.ViewPropertyAnimator rotationX(float);
-    method public android.view.ViewPropertyAnimator rotationXBy(float);
-    method public android.view.ViewPropertyAnimator rotationY(float);
-    method public android.view.ViewPropertyAnimator rotationYBy(float);
-    method public android.view.ViewPropertyAnimator scaleX(float);
-    method public android.view.ViewPropertyAnimator scaleXBy(float);
-    method public android.view.ViewPropertyAnimator scaleY(float);
-    method public android.view.ViewPropertyAnimator scaleYBy(float);
-    method public android.view.ViewPropertyAnimator setDuration(long);
-    method public android.view.ViewPropertyAnimator setInterpolator(android.animation.TimeInterpolator);
-    method public android.view.ViewPropertyAnimator setListener(android.animation.Animator.AnimatorListener);
-    method public android.view.ViewPropertyAnimator setStartDelay(long);
-    method public android.view.ViewPropertyAnimator setUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
+    method @NonNull public android.view.ViewPropertyAnimator rotation(float);
+    method @NonNull public android.view.ViewPropertyAnimator rotationBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator rotationX(float);
+    method @NonNull public android.view.ViewPropertyAnimator rotationXBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator rotationY(float);
+    method @NonNull public android.view.ViewPropertyAnimator rotationYBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator scaleX(float);
+    method @NonNull public android.view.ViewPropertyAnimator scaleXBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator scaleY(float);
+    method @NonNull public android.view.ViewPropertyAnimator scaleYBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator setDuration(long);
+    method @NonNull public android.view.ViewPropertyAnimator setInterpolator(android.animation.TimeInterpolator);
+    method @NonNull public android.view.ViewPropertyAnimator setListener(@Nullable android.animation.Animator.AnimatorListener);
+    method @NonNull public android.view.ViewPropertyAnimator setStartDelay(long);
+    method @NonNull public android.view.ViewPropertyAnimator setUpdateListener(@Nullable android.animation.ValueAnimator.AnimatorUpdateListener);
     method public void start();
-    method public android.view.ViewPropertyAnimator translationX(float);
-    method public android.view.ViewPropertyAnimator translationXBy(float);
-    method public android.view.ViewPropertyAnimator translationY(float);
-    method public android.view.ViewPropertyAnimator translationYBy(float);
-    method public android.view.ViewPropertyAnimator translationZ(float);
-    method public android.view.ViewPropertyAnimator translationZBy(float);
-    method public android.view.ViewPropertyAnimator withEndAction(Runnable);
-    method public android.view.ViewPropertyAnimator withLayer();
-    method public android.view.ViewPropertyAnimator withStartAction(Runnable);
-    method public android.view.ViewPropertyAnimator x(float);
-    method public android.view.ViewPropertyAnimator xBy(float);
-    method public android.view.ViewPropertyAnimator y(float);
-    method public android.view.ViewPropertyAnimator yBy(float);
-    method public android.view.ViewPropertyAnimator z(float);
-    method public android.view.ViewPropertyAnimator zBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator translationX(float);
+    method @NonNull public android.view.ViewPropertyAnimator translationXBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator translationY(float);
+    method @NonNull public android.view.ViewPropertyAnimator translationYBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator translationZ(float);
+    method @NonNull public android.view.ViewPropertyAnimator translationZBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator withEndAction(Runnable);
+    method @NonNull public android.view.ViewPropertyAnimator withLayer();
+    method @NonNull public android.view.ViewPropertyAnimator withStartAction(Runnable);
+    method @NonNull public android.view.ViewPropertyAnimator x(float);
+    method @NonNull public android.view.ViewPropertyAnimator xBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator y(float);
+    method @NonNull public android.view.ViewPropertyAnimator yBy(float);
+    method @NonNull public android.view.ViewPropertyAnimator z(float);
+    method @NonNull public android.view.ViewPropertyAnimator zBy(float);
   }
 
   public abstract class ViewStructure {
@@ -51497,6 +51425,7 @@
     method public CharSequence getPackageName();
     method public android.view.accessibility.AccessibilityRecord getRecord(int);
     method public int getRecordCount();
+    method public int getSpeechStateChangeTypes();
     method public int getWindowChanges();
     method public void initFromParcel(android.os.Parcel);
     method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(int);
@@ -51508,6 +51437,7 @@
     method public void setEventType(int);
     method public void setMovementGranularity(int);
     method public void setPackageName(CharSequence);
+    method public void setSpeechStateChangeTypes(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
     field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
@@ -51523,12 +51453,17 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityEvent> CREATOR;
     field public static final int INVALID_POSITION = -1; // 0xffffffff
     field @Deprecated public static final int MAX_TEXT_LENGTH = 500; // 0x1f4
+    field public static final int SPEECH_STATE_LISTENING_END = 8; // 0x8
+    field public static final int SPEECH_STATE_LISTENING_START = 4; // 0x4
+    field public static final int SPEECH_STATE_SPEAKING_END = 2; // 0x2
+    field public static final int SPEECH_STATE_SPEAKING_START = 1; // 0x1
     field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
     field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
     field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
     field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
     field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
     field public static final int TYPE_NOTIFICATION_STATE_CHANGED = 64; // 0x40
+    field public static final int TYPE_SPEECH_STATE_CHANGE = 33554432; // 0x2000000
     field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
     field public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
     field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
@@ -51943,10 +51878,10 @@
   public abstract class AccessibilityNodeProvider {
     ctor public AccessibilityNodeProvider();
     method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, String, android.os.Bundle);
-    method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
-    method public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String, int);
-    method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
-    method public boolean performAction(int, int, android.os.Bundle);
+    method @Nullable public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
+    method @Nullable public java.util.List<android.view.accessibility.AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String, int);
+    method @Nullable public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
+    method public boolean performAction(int, int, @Nullable android.os.Bundle);
     field public static final int HOST_VIEW_ID = -1; // 0xffffffff
   }
 
@@ -51954,23 +51889,23 @@
     ctor public AccessibilityRecord();
     ctor public AccessibilityRecord(@NonNull android.view.accessibility.AccessibilityRecord);
     method public int getAddedCount();
-    method public CharSequence getBeforeText();
-    method public CharSequence getClassName();
-    method public CharSequence getContentDescription();
+    method @Nullable public CharSequence getBeforeText();
+    method @Nullable public CharSequence getClassName();
+    method @Nullable public CharSequence getContentDescription();
     method public int getCurrentItemIndex();
     method public int getDisplayId();
     method public int getFromIndex();
     method public int getItemCount();
     method public int getMaxScrollX();
     method public int getMaxScrollY();
-    method public android.os.Parcelable getParcelableData();
+    method @Nullable public android.os.Parcelable getParcelableData();
     method public int getRemovedCount();
     method public int getScrollDeltaX();
     method public int getScrollDeltaY();
     method public int getScrollX();
     method public int getScrollY();
-    method public android.view.accessibility.AccessibilityNodeInfo getSource();
-    method public java.util.List<java.lang.CharSequence> getText();
+    method @Nullable public android.view.accessibility.AccessibilityNodeInfo getSource();
+    method @NonNull public java.util.List<java.lang.CharSequence> getText();
     method public int getToIndex();
     method public int getWindowId();
     method public boolean isChecked();
@@ -51978,14 +51913,14 @@
     method public boolean isFullScreen();
     method public boolean isPassword();
     method public boolean isScrollable();
-    method @Deprecated public static android.view.accessibility.AccessibilityRecord obtain(android.view.accessibility.AccessibilityRecord);
-    method @Deprecated public static android.view.accessibility.AccessibilityRecord obtain();
+    method @Deprecated @NonNull public static android.view.accessibility.AccessibilityRecord obtain(@NonNull android.view.accessibility.AccessibilityRecord);
+    method @Deprecated @NonNull public static android.view.accessibility.AccessibilityRecord obtain();
     method @Deprecated public void recycle();
     method public void setAddedCount(int);
-    method public void setBeforeText(CharSequence);
+    method public void setBeforeText(@Nullable CharSequence);
     method public void setChecked(boolean);
-    method public void setClassName(CharSequence);
-    method public void setContentDescription(CharSequence);
+    method public void setClassName(@Nullable CharSequence);
+    method public void setContentDescription(@Nullable CharSequence);
     method public void setCurrentItemIndex(int);
     method public void setEnabled(boolean);
     method public void setFromIndex(int);
@@ -51993,7 +51928,7 @@
     method public void setItemCount(int);
     method public void setMaxScrollX(int);
     method public void setMaxScrollY(int);
-    method public void setParcelableData(android.os.Parcelable);
+    method public void setParcelableData(@Nullable android.os.Parcelable);
     method public void setPassword(boolean);
     method public void setRemovedCount(int);
     method public void setScrollDeltaX(int);
@@ -52001,7 +51936,7 @@
     method public void setScrollX(int);
     method public void setScrollY(int);
     method public void setScrollable(boolean);
-    method public void setSource(android.view.View);
+    method public void setSource(@Nullable android.view.View);
     method public void setSource(@Nullable android.view.View, int);
     method public void setToIndex(int);
   }
@@ -52324,7 +52259,7 @@
   }
 
   public class PathInterpolator extends android.view.animation.BaseInterpolator {
-    ctor public PathInterpolator(android.graphics.Path);
+    ctor public PathInterpolator(@NonNull android.graphics.Path);
     ctor public PathInterpolator(float, float);
     ctor public PathInterpolator(float, float, float, float);
     ctor public PathInterpolator(android.content.Context, android.util.AttributeSet);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 4448a03..36d54f5 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -86,31 +86,6 @@
 
 }
 
-package android.app.usage {
-
-  public class NetworkStatsManager {
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void forceUpdate();
-    method public static int getCollapsedRatType(int);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyNetworkStatus(@NonNull java.util.List<android.net.Network>, @NonNull java.util.List<android.net.NetworkStateSnapshot>, @Nullable String, @NonNull java.util.List<android.net.UnderlyingNetworkInfo>);
-    method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForDevice(@NonNull android.net.NetworkTemplate, long, long);
-    method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(@NonNull android.net.NetworkTemplate, long, long, int, int, int) throws java.lang.SecurityException;
-    method @NonNull @WorkerThread public android.app.usage.NetworkStats querySummary(@NonNull android.net.NetworkTemplate, long, long) throws java.lang.SecurityException;
-    method @NonNull @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(@NonNull android.net.NetworkTemplate, long, long);
-    method @NonNull @WorkerThread public android.app.usage.NetworkStats queryTaggedSummary(@NonNull android.net.NetworkTemplate, long, long) throws java.lang.SecurityException;
-    method public void registerUsageCallback(@NonNull android.net.NetworkTemplate, long, @NonNull java.util.concurrent.Executor, @NonNull android.app.usage.NetworkStatsManager.UsageCallback);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setDefaultGlobalAlert(long);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setPollOnOpen(boolean);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setStatsProviderWarningAndLimitAsync(@NonNull String, long, long);
-    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setUidForeground(int, boolean);
-    field public static final int NETWORK_TYPE_5G_NSA = -2; // 0xfffffffe
-  }
-
-  public abstract static class NetworkStatsManager.UsageCallback {
-    method public void onThresholdReached(@NonNull android.net.NetworkTemplate);
-  }
-
-}
-
 package android.content {
 
   public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
@@ -139,9 +114,14 @@
 
 package android.content.pm {
 
+  public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    method @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraryInfos();
+  }
+
   public abstract class PackageManager {
     method @NonNull public String getPermissionControllerPackageName();
     method @NonNull public String getSupplementalProcessPackageName();
+    field public static final int MATCH_STATIC_SHARED_AND_SDK_LIBRARIES = 67108864; // 0x4000000
   }
 
 }
@@ -278,44 +258,10 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR;
   }
 
-  public final class IpSecManager {
-    field public static final int DIRECTION_FWD = 2; // 0x2
-  }
-
-  public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
-    method public int getResourceId();
-  }
-
   public class LocalSocket implements java.io.Closeable {
     ctor public LocalSocket(@NonNull java.io.FileDescriptor);
   }
 
-  public class NetworkIdentity {
-    method public int getOemManaged();
-    method public int getRatType();
-    method @Nullable public String getSubscriberId();
-    method public int getType();
-    method @Nullable public String getWifiNetworkKey();
-    method public boolean isDefaultNetwork();
-    method public boolean isMetered();
-    method public boolean isRoaming();
-  }
-
-  public static final class NetworkIdentity.Builder {
-    ctor public NetworkIdentity.Builder();
-    method @NonNull public android.net.NetworkIdentity build();
-    method @NonNull public android.net.NetworkIdentity.Builder clearRatType();
-    method @NonNull public android.net.NetworkIdentity.Builder setDefaultNetwork(boolean);
-    method @NonNull public android.net.NetworkIdentity.Builder setMetered(boolean);
-    method @NonNull public android.net.NetworkIdentity.Builder setNetworkStateSnapshot(@NonNull android.net.NetworkStateSnapshot);
-    method @NonNull public android.net.NetworkIdentity.Builder setOemManaged(int);
-    method @NonNull public android.net.NetworkIdentity.Builder setRatType(int);
-    method @NonNull public android.net.NetworkIdentity.Builder setRoaming(boolean);
-    method @NonNull public android.net.NetworkIdentity.Builder setSubscriberId(@Nullable String);
-    method @NonNull public android.net.NetworkIdentity.Builder setType(int);
-    method @NonNull public android.net.NetworkIdentity.Builder setWifiNetworkKey(@Nullable String);
-  }
-
   public class NetworkPolicyManager {
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getMultipathPreference(@NonNull android.net.Network);
     method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getRestrictBackgroundStatus(int);
@@ -331,94 +277,6 @@
     method public default void onUidBlockedReasonChanged(int, int);
   }
 
-  public final class NetworkStateSnapshot implements android.os.Parcelable {
-    ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int);
-    method public int describeContents();
-    method public int getLegacyType();
-    method @NonNull public android.net.LinkProperties getLinkProperties();
-    method @NonNull public android.net.Network getNetwork();
-    method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
-    method @Nullable public String getSubscriberId();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStateSnapshot> CREATOR;
-  }
-
-  public class NetworkStatsCollection {
-    method @NonNull public java.util.Map<android.net.NetworkStatsCollection.Key,android.net.NetworkStatsHistory> getEntries();
-  }
-
-  public static final class NetworkStatsCollection.Builder {
-    ctor public NetworkStatsCollection.Builder(long);
-    method @NonNull public android.net.NetworkStatsCollection.Builder addEntry(@NonNull android.net.NetworkStatsCollection.Key, @NonNull android.net.NetworkStatsHistory);
-    method @NonNull public android.net.NetworkStatsCollection build();
-  }
-
-  public static class NetworkStatsCollection.Key {
-    ctor public NetworkStatsCollection.Key(@NonNull java.util.Set<android.net.NetworkIdentity>, int, int, int);
-  }
-
-  public final class NetworkStatsHistory implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public java.util.List<android.net.NetworkStatsHistory.Entry> getEntries();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStatsHistory> CREATOR;
-  }
-
-  public static final class NetworkStatsHistory.Builder {
-    ctor public NetworkStatsHistory.Builder(long, int);
-    method @NonNull public android.net.NetworkStatsHistory.Builder addEntry(@NonNull android.net.NetworkStatsHistory.Entry);
-    method @NonNull public android.net.NetworkStatsHistory build();
-  }
-
-  public static final class NetworkStatsHistory.Entry {
-    ctor public NetworkStatsHistory.Entry(long, long, long, long, long, long, long);
-    method public long getActiveTime();
-    method public long getBucketStart();
-    method public long getOperations();
-    method public long getRxBytes();
-    method public long getRxPackets();
-    method public long getTxBytes();
-    method public long getTxPackets();
-  }
-
-  public final class NetworkTemplate implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getDefaultNetworkStatus();
-    method public int getMatchRule();
-    method public int getMeteredness();
-    method public int getOemManaged();
-    method public int getRatType();
-    method public int getRoaming();
-    method @NonNull public java.util.Set<java.lang.String> getSubscriberIds();
-    method @NonNull public java.util.Set<java.lang.String> getWifiNetworkKeys();
-    method public boolean matches(@NonNull android.net.NetworkIdentity);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkTemplate> CREATOR;
-    field public static final int MATCH_BLUETOOTH = 8; // 0x8
-    field public static final int MATCH_CARRIER = 10; // 0xa
-    field public static final int MATCH_ETHERNET = 5; // 0x5
-    field public static final int MATCH_MOBILE = 1; // 0x1
-    field public static final int MATCH_WIFI = 4; // 0x4
-    field public static final int NETWORK_TYPE_ALL = -1; // 0xffffffff
-    field public static final int OEM_MANAGED_ALL = -1; // 0xffffffff
-    field public static final int OEM_MANAGED_NO = 0; // 0x0
-    field public static final int OEM_MANAGED_PAID = 1; // 0x1
-    field public static final int OEM_MANAGED_PRIVATE = 2; // 0x2
-    field public static final int OEM_MANAGED_YES = -2; // 0xfffffffe
-  }
-
-  public static final class NetworkTemplate.Builder {
-    ctor public NetworkTemplate.Builder(int);
-    method @NonNull public android.net.NetworkTemplate build();
-    method @NonNull public android.net.NetworkTemplate.Builder setDefaultNetworkStatus(int);
-    method @NonNull public android.net.NetworkTemplate.Builder setMeteredness(int);
-    method @NonNull public android.net.NetworkTemplate.Builder setOemManaged(int);
-    method @NonNull public android.net.NetworkTemplate.Builder setRatType(int);
-    method @NonNull public android.net.NetworkTemplate.Builder setRoaming(int);
-    method @NonNull public android.net.NetworkTemplate.Builder setSubscriberIds(@NonNull java.util.Set<java.lang.String>);
-    method @NonNull public android.net.NetworkTemplate.Builder setWifiNetworkKeys(@NonNull java.util.Set<java.lang.String>);
-  }
-
   public class NetworkWatchlistManager {
     method @Nullable public byte[] getWatchlistConfigHash();
   }
@@ -437,21 +295,6 @@
     method public static void setHttpProxyConfiguration(@Nullable android.net.ProxyInfo);
   }
 
-  public class TrafficStats {
-    method public static void attachSocketTagger();
-    method public static void init(@NonNull android.content.Context);
-  }
-
-  public final class UnderlyingNetworkInfo implements android.os.Parcelable {
-    ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>);
-    method public int describeContents();
-    method @NonNull public String getInterface();
-    method public int getOwnerUid();
-    method @NonNull public java.util.List<java.lang.String> getUnderlyingInterfaces();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.UnderlyingNetworkInfo> CREATOR;
-  }
-
   public class VpnManager {
     field public static final int TYPE_VPN_LEGACY = 3; // 0x3
     field public static final int TYPE_VPN_NONE = -1; // 0xffffffff
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 311b110..608a9a4 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -250,10 +250,6 @@
     method @Deprecated public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
   }
 
-  public class TrafficStats {
-    method @Deprecated public static void setThreadStatsUidSelf();
-  }
-
 }
 
 package android.os {
@@ -513,7 +509,7 @@
 
 package android.view {
 
-  @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback android.view.OnBackInvokedDispatcherOwner {
+  @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
     method protected void initializeFadingEdge(android.content.res.TypedArray);
     method protected void initializeScrollbars(android.content.res.TypedArray);
   }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d5c35cd..6267dbf3 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -166,6 +166,7 @@
     field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
     field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
     field public static final String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
+    field public static final String MANAGE_ETHERNET_NETWORKS = "android.permission.MANAGE_ETHERNET_NETWORKS";
     field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
     field public static final String MANAGE_GAME_ACTIVITY = "android.permission.MANAGE_GAME_ACTIVITY";
     field public static final String MANAGE_GAME_MODE = "android.permission.MANAGE_GAME_MODE";
@@ -1084,6 +1085,7 @@
     method public boolean isDeviceManaged();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean isDpcDownloaded();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isManagedKiosk();
     method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isUnattendedManagedKiosk();
@@ -1096,6 +1098,7 @@
     method @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     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 @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
     method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
     method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
@@ -1174,6 +1177,13 @@
     field public static final String UNDEFINED = "UNDEFINED";
   }
 
+  public static final class DevicePolicyResources.Strings.Dialer {
+    field public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE";
+    field public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE = "Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE";
+    field public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE";
+    field public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL = "Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL";
+  }
+
   public static final class DevicePolicyResources.Strings.DocumentsUi {
     field public static final String CANT_SAVE_TO_PERSONAL_MESSAGE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE";
     field public static final String CANT_SAVE_TO_PERSONAL_TITLE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE";
@@ -2250,9 +2260,9 @@
   public static final class SmartspaceCarouselUiTemplateData.CarouselItem implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getImage();
-    method @Nullable public CharSequence getLowerText();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getLowerText();
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getTapAction();
-    method @Nullable public CharSequence getUpperText();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getUpperText();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem> CREATOR;
   }
@@ -2261,9 +2271,9 @@
     ctor public SmartspaceCarouselUiTemplateData.CarouselItem.Builder();
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem build();
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setImage(@Nullable android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setLowerText(@Nullable CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setLowerText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setTapAction(@Nullable android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setUpperText(@Nullable CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setUpperText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
   }
 
   public final class SmartspaceCombinedCardsUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
@@ -2279,15 +2289,15 @@
   public class SmartspaceDefaultUiTemplateData implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getPrimaryTapAction();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubTitleIcon();
-    method @Nullable public CharSequence getSubtitleText();
-    method @Nullable public CharSequence getSupplementalAlarmText();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubtitleIcon();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSubtitleText();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSupplementalAlarmText();
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSupplementalSubtitleIcon();
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSupplementalSubtitleTapAction();
-    method @Nullable public CharSequence getSupplementalSubtitleText();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSupplementalSubtitleText();
     method public int getTemplateType();
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getTitleIcon();
-    method @Nullable public CharSequence getTitleText();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getTitleText();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData> CREATOR;
   }
@@ -2296,23 +2306,23 @@
     ctor public SmartspaceDefaultUiTemplateData.Builder(int);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData build();
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setPrimaryTapAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubTitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubtitleText(@NonNull CharSequence);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalAlarmText(@NonNull CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubtitleText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalAlarmText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleTapAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleText(@NonNull CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setTitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setTitleText(@NonNull CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setTitleText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
   }
 
   public final class SmartspaceHeadToHeadUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getHeadToHeadAction();
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getHeadToHeadFirstCompetitorIcon();
-    method @Nullable public CharSequence getHeadToHeadFirstCompetitorText();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getHeadToHeadFirstCompetitorText();
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getHeadToHeadSecondCompetitorIcon();
-    method @Nullable public CharSequence getHeadToHeadSecondCompetitorText();
-    method @Nullable public CharSequence getHeadToHeadTitle();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getHeadToHeadSecondCompetitorText();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getHeadToHeadTitle();
     field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData> CREATOR;
   }
 
@@ -2321,16 +2331,17 @@
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData build();
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadAction(@Nullable android.app.smartspace.uitemplatedata.SmartspaceTapAction);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadFirstCompetitorIcon(@Nullable android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadFirstCompetitorText(@Nullable CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadFirstCompetitorText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadSecondCompetitorIcon(@Nullable android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadSecondCompetitorText(@Nullable CharSequence);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadTitle(@Nullable CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadSecondCompetitorText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadTitle(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
   }
 
   public final class SmartspaceIcon implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public CharSequence getContentDescription();
     method @NonNull public android.graphics.drawable.Icon getIcon();
+    method public boolean shouldTint();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceIcon> CREATOR;
   }
@@ -2339,46 +2350,47 @@
     ctor public SmartspaceIcon.Builder(@NonNull android.graphics.drawable.Icon);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon build();
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon.Builder setContentDescription(@NonNull CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon.Builder setShouldTint(boolean);
   }
 
   public final class SmartspaceSubCardUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSubCardAction();
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubCardIcon();
-    method @Nullable public CharSequence getSubCardText();
+    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSubCardText();
     field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData> CREATOR;
   }
 
   public static final class SmartspaceSubCardUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder {
     ctor public SmartspaceSubCardUiTemplateData.Builder(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData.Builder setSubCardAction(@NonNull CharSequence);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData.Builder setSubCardAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData.Builder setSubCardText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
   }
 
   public final class SmartspaceSubImageUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSubImageAction();
-    method @NonNull public java.util.List<java.lang.CharSequence> getSubImageTexts();
+    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText> getSubImageTexts();
     method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceIcon> getSubImages();
     field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData> CREATOR;
   }
 
   public static final class SmartspaceSubImageUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder {
-    ctor public SmartspaceSubImageUiTemplateData.Builder(@NonNull java.util.List<java.lang.CharSequence>, @NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceIcon>);
+    ctor public SmartspaceSubImageUiTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText>, @NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceIcon>);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData.Builder setCarouselAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData.Builder setSubImageAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
   }
 
   public final class SmartspaceSubListUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSubListAction();
     method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubListIcon();
-    method @NonNull public java.util.List<java.lang.CharSequence> getSubListTexts();
+    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText> getSubListTexts();
     field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData> CREATOR;
   }
 
   public static final class SmartspaceSubListUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder {
-    ctor public SmartspaceSubListUiTemplateData.Builder(@NonNull java.util.List<java.lang.CharSequence>);
+    ctor public SmartspaceSubListUiTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText>);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData.Builder setCarouselAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData.Builder setSubListAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData.Builder setSubListIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
   }
 
@@ -2402,6 +2414,21 @@
     method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceTapAction.Builder setUserHandle(@Nullable android.os.UserHandle);
   }
 
+  public final class SmartspaceText implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public CharSequence getText();
+    method @NonNull public android.text.TextUtils.TruncateAt getTruncateAtType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceText> CREATOR;
+  }
+
+  public static final class SmartspaceText.Builder {
+    ctor public SmartspaceText.Builder(@NonNull CharSequence);
+    ctor public SmartspaceText.Builder(@NonNull CharSequence, @NonNull android.text.TextUtils.TruncateAt);
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceText build();
+    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceText.Builder setTruncateAtType(@NonNull android.text.TextUtils.TruncateAt);
+  }
+
 }
 
 package android.app.time {
@@ -2511,13 +2538,6 @@
     field public static final String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService";
   }
 
-  public class NetworkStatsManager {
-    method @NonNull @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public android.net.NetworkStats getMobileUidStats();
-    method @NonNull @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public android.net.NetworkStats getWifiUidStats();
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void registerNetworkStatsProvider(@NonNull String, @NonNull android.net.netstats.provider.NetworkStatsProvider);
-    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void unregisterNetworkStatsProvider(@NonNull android.net.netstats.provider.NetworkStatsProvider);
-  }
-
   public static final class UsageEvents.Event {
     method public int getInstanceId();
     method @Nullable public String getNotificationChannelId();
@@ -2741,6 +2761,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
     method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.LaunchCallback);
     method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
+    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean);
   }
 
   public final class VirtualDeviceParams implements android.os.Parcelable {
@@ -5925,11 +5946,20 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioAttributes.Builder setSystemUsage(int);
   }
 
+  public class AudioDescriptor implements android.os.Parcelable {
+    ctor public AudioDescriptor(int, int, @NonNull byte[]);
+  }
+
   public final class AudioDeviceAttributes implements android.os.Parcelable {
     ctor public AudioDeviceAttributes(@NonNull android.media.AudioDeviceInfo);
     ctor public AudioDeviceAttributes(int, int, @NonNull String);
+    ctor public AudioDeviceAttributes(int, int, @NonNull String, @NonNull String, @NonNull java.util.List<android.media.AudioProfile>, @NonNull java.util.List<android.media.AudioDescriptor>);
     method public int describeContents();
+    method public boolean equalTypeAddress(@Nullable Object);
     method @NonNull public String getAddress();
+    method @NonNull public java.util.List<android.media.AudioDescriptor> getAudioDescriptors();
+    method @NonNull public java.util.List<android.media.AudioProfile> getAudioProfiles();
+    method @NonNull public String getName();
     method public int getRole();
     method public int getType();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -6086,6 +6116,10 @@
     field public static final int PLAYER_TYPE_UNKNOWN = -1; // 0xffffffff
   }
 
+  public class AudioProfile implements android.os.Parcelable {
+    ctor public AudioProfile(int, @NonNull int[], @NonNull int[], @NonNull int[], int);
+  }
+
   public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {
     ctor @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
     method public static long getMaxSharedAudioHistoryMillis();
@@ -7032,8 +7066,8 @@
     method @Nullable public String acquireSharedFilterToken();
     method public void close();
     method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
+    method public int delayCallbackForDurationMillis(long);
     method public int delayCallbackUntilBytesAccumulated(int);
-    method public int delayCallbackUntilMillisElapsed(long);
     method public int flush();
     method public void freeSharedFilterToken(@NonNull String);
     method @Deprecated public int getId();
@@ -7952,7 +7986,7 @@
 
   public class FrontendStatus {
     method public int getAgc();
-    method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpInfo[] getAllAtsc3PlpInfo();
+    method @NonNull public java.util.List<android.media.tv.tuner.frontend.Atsc3PlpInfo> getAllAtsc3PlpInfo();
     method @NonNull public android.media.tv.tuner.frontend.FrontendStatus.Atsc3PlpTuningInfo[] getAtsc3PlpTuningInfo();
     method public int getBandwidth();
     method public int getBer();
@@ -8324,7 +8358,10 @@
 package android.net {
 
   public class EthernetManager {
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void connectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void disconnectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void updateConfiguration(@NonNull String, @NonNull android.net.EthernetNetworkUpdateRequest, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.BiConsumer<android.net.Network,android.net.EthernetNetworkManagementException>);
   }
 
   public static interface EthernetManager.TetheredInterfaceCallback {
@@ -8336,21 +8373,20 @@
     method public void release();
   }
 
-  public final class IpSecManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
-    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+  public final class EthernetNetworkManagementException extends java.lang.RuntimeException implements android.os.Parcelable {
+    ctor public EthernetNetworkManagementException(@NonNull String);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkManagementException> CREATOR;
   }
 
-  public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
-    method public void close();
-    method @NonNull public String getInterfaceName();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void setUnderlyingNetwork(@NonNull android.net.Network) throws java.io.IOException;
-  }
-
-  public static class IpSecTransform.Builder {
-    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+  public final class EthernetNetworkUpdateRequest implements android.os.Parcelable {
+    ctor public EthernetNetworkUpdateRequest(@NonNull android.net.StaticIpConfiguration, @NonNull android.net.NetworkCapabilities);
+    method public int describeContents();
+    method @NonNull public android.net.StaticIpConfiguration getIpConfig();
+    method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR;
   }
 
   public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
@@ -8414,48 +8450,6 @@
     field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
   }
 
-  public final class NetworkStats implements java.lang.Iterable<android.net.NetworkStats.Entry> android.os.Parcelable {
-    ctor public NetworkStats(long, int);
-    method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats);
-    method @NonNull public android.net.NetworkStats addEntry(@NonNull android.net.NetworkStats.Entry);
-    method public int describeContents();
-    method @NonNull public java.util.Iterator<android.net.NetworkStats.Entry> iterator();
-    method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR;
-    field public static final int DEFAULT_NETWORK_ALL = -1; // 0xffffffff
-    field public static final int DEFAULT_NETWORK_NO = 0; // 0x0
-    field public static final int DEFAULT_NETWORK_YES = 1; // 0x1
-    field public static final String IFACE_VT = "vt_data0";
-    field public static final int METERED_ALL = -1; // 0xffffffff
-    field public static final int METERED_NO = 0; // 0x0
-    field public static final int METERED_YES = 1; // 0x1
-    field public static final int ROAMING_ALL = -1; // 0xffffffff
-    field public static final int ROAMING_NO = 0; // 0x0
-    field public static final int ROAMING_YES = 1; // 0x1
-    field public static final int SET_ALL = -1; // 0xffffffff
-    field public static final int SET_DEFAULT = 0; // 0x0
-    field public static final int SET_FOREGROUND = 1; // 0x1
-    field public static final int TAG_NONE = 0; // 0x0
-    field public static final int UID_ALL = -1; // 0xffffffff
-    field public static final int UID_TETHERING = -5; // 0xfffffffb
-  }
-
-  public static class NetworkStats.Entry {
-    ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
-    method public int getDefaultNetwork();
-    method public int getMetered();
-    method public long getOperations();
-    method public int getRoaming();
-    method public long getRxBytes();
-    method public long getRxPackets();
-    method public int getSet();
-    method public int getTag();
-    method public long getTxBytes();
-    method public long getTxPackets();
-    method public int getUid();
-  }
-
   @Deprecated public class RssiCurve implements android.os.Parcelable {
     ctor @Deprecated public RssiCurve(int, int, byte[]);
     ctor @Deprecated public RssiCurve(int, int, byte[], int);
@@ -8487,19 +8481,6 @@
     field @Deprecated public final android.net.RssiCurve rssiCurve;
   }
 
-  public class TrafficStats {
-    method public static void setThreadStatsTagApp();
-    method public static void setThreadStatsTagBackup();
-    method public static void setThreadStatsTagDownload();
-    method public static void setThreadStatsTagRestore();
-    field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = -113; // 0xffffff8f
-    field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = -128; // 0xffffff80
-    field public static final int TAG_NETWORK_STACK_RANGE_END = -257; // 0xfffffeff
-    field public static final int TAG_NETWORK_STACK_RANGE_START = -768; // 0xfffffd00
-    field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = -241; // 0xffffff0f
-    field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00
-  }
-
   public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
     method @NonNull public String toSafeString();
   }
@@ -8680,23 +8661,6 @@
 
 }
 
-package android.net.netstats.provider {
-
-  public abstract class NetworkStatsProvider {
-    ctor public NetworkStatsProvider();
-    method public void notifyAlertReached();
-    method public void notifyLimitReached();
-    method public void notifyStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats);
-    method public void notifyWarningReached();
-    method public abstract void onRequestStatsUpdate(int);
-    method public abstract void onSetAlert(long);
-    method public abstract void onSetLimit(@NonNull String, long);
-    method public void onSetWarningAndLimit(@NonNull String, long, long);
-    field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff
-  }
-
-}
-
 package android.net.sip {
 
   @Deprecated public class SipAudioCall {
@@ -9668,7 +9632,7 @@
     method @NonNull public java.util.List<android.os.UserHandle> getAllProfiles();
     method @NonNull public java.util.List<android.os.UserHandle> getEnabledProfiles();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String, boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableUserCount(@NonNull String);
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getRestrictedProfileParent();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
@@ -9964,7 +9928,8 @@
     method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
     method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
     method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, long, int, int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
     field @RequiresPermission(android.Manifest.permission.START_REVIEW_PERMISSION_DECISIONS) public static final String ACTION_REVIEW_PERMISSION_DECISIONS = "android.permission.action.REVIEW_PERMISSION_DECISIONS";
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -10413,8 +10378,6 @@
   }
 
   public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
-    method public static int getIntForUser(@NonNull android.content.ContentResolver, @NonNull String, int, int);
-    method @Nullable public static String getStringForUser(@NonNull android.content.ContentResolver, @NonNull String, int);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, @Nullable String, boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
     field @Deprecated public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = "accessibility_display_magnification_navbar_enabled";
@@ -11138,6 +11101,7 @@
     field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
     field public static final String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT";
     field public static final String EXTRA_RESOLUTION_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_PORT_INDEX";
+    field public static final String EXTRA_RESOLUTION_SUBSCRIPTION_ID = "android.service.euicc.extra.RESOLUTION_SUBSCRIPTION_ID";
     field public static final String EXTRA_RESOLUTION_USE_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_USE_PORT_INDEX";
     field public static final String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS";
     field public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1; // 0x1
@@ -11214,6 +11178,7 @@
     method public void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean);
     method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final boolean restartGame();
     method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final void startActivityFromGameSessionForResult(@NonNull android.content.Intent, @Nullable android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSessionActivityCallback);
     method public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
   }
 
@@ -11223,6 +11188,11 @@
     field public static final int ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR = 0; // 0x0
   }
 
+  public interface GameSessionActivityCallback {
+    method public void onActivityResult(int, @Nullable android.content.Intent);
+    method public default void onActivityStartFailed(@NonNull Throwable);
+  }
+
   public abstract class GameSessionService extends android.app.Service {
     ctor public GameSessionService();
     method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
@@ -12251,6 +12221,7 @@
     field public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; // 0x2
     field public static final int CALL_SOURCE_UNSPECIFIED = 0; // 0x0
     field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
+    field public static final String EXTRA_CALL_HAS_IN_BAND_RINGTONE = "android.telecom.extra.CALL_HAS_IN_BAND_RINGTONE";
     field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
     field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
     field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
@@ -13194,7 +13165,6 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesBitmask();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesForReason(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
@@ -13240,7 +13210,6 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimCardState(int, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Locale getSimLocale();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Collection<android.telephony.UiccSlotMapping> getSimSlotMapping();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telephony.RadioAccessSpecifier> getSystemSelectionChannels();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
@@ -13295,7 +13264,6 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int sendThermalMitigationRequest(@NonNull android.telephony.ThermalMitigationRequest);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAllowedNetworkTypesForReason(int, long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
@@ -13345,10 +13313,8 @@
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
-    field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2
     field public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; // 0x3
     field public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; // 0x1
-    field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0
     field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2
     field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1
     field public static final int CALL_WAITING_STATUS_FDN_CHECK_FAILURE = 5; // 0x5
@@ -13388,26 +13354,6 @@
     field public static final int KEY_TYPE_WLAN = 2; // 0x2
     field public static final int MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL = 1; // 0x1
     field public static final int MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED = 2; // 0x2
-    field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L
-    field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L
-    field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L
-    field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L
-    field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L
-    field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L
-    field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L
-    field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L
-    field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L
-    field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L
-    field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L
-    field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L
-    field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L
-    field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L
-    field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L
-    field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L
-    field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L
-    field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L
-    field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L
-    field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L
     field public static final int NR_DUAL_CONNECTIVITY_DISABLE = 2; // 0x2
     field public static final int NR_DUAL_CONNECTIVITY_DISABLE_IMMEDIATE = 3; // 0x3
     field public static final int NR_DUAL_CONNECTIVITY_ENABLE = 1; // 0x1
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index e17a9bb..1b45e88 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -1,11 +1,5 @@
 // Baseline format: 1.0
 ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
-    
-
-
-BuilderSetStyle: android.net.IpSecTransform.Builder#buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex):
-    Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.net.IpSecTransform.Builder.buildTunnelModeTransform(java.net.InetAddress,android.net.IpSecManager.SecurityParameterIndex)
-
 
 ExecutorRegistration: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
     Registration methods should have overload that accepts delivery Executor: `setOnRtpRxNoticeListener`
@@ -15,8 +9,6 @@
     
 GenericException: android.hardware.location.ContextHubClient#finalize():
     
-GenericException: android.net.IpSecManager.IpSecTunnelInterface#finalize():
-    
 GenericException: android.service.autofill.augmented.FillWindow#finalize():
     
 
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index fea7396..4132c64 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -511,6 +511,8 @@
     field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
     field public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED";
     field @Deprecated public static final int CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER = 14; // 0xe
+    field public static final int DEVICE_OWNER_TYPE_DEFAULT = 0; // 0x0
+    field public static final int DEVICE_OWNER_TYPE_FINANCED = 1; // 0x1
     field public static final int OPERATION_CLEAR_APPLICATION_USER_DATA = 23; // 0x17
     field public static final int OPERATION_CREATE_AND_MANAGE_USER = 5; // 0x5
     field public static final int OPERATION_INSTALL_CA_CERT = 24; // 0x18
@@ -614,10 +616,6 @@
 
 package android.app.usage {
 
-  public class NetworkStatsManager {
-    method public void setPollForce(boolean);
-  }
-
   public class StorageStatsManager {
     method public boolean isQuotaSupported(@NonNull java.util.UUID);
     method public boolean isReservedSupported(@NonNull java.util.UUID);
@@ -668,6 +666,7 @@
     ctor public AttributionSource(int, @Nullable String, @Nullable String);
     ctor public AttributionSource(int, @Nullable String, @Nullable String, @NonNull android.os.IBinder);
     ctor public AttributionSource(int, @Nullable String, @Nullable String, @Nullable java.util.Set<java.lang.String>, @Nullable android.content.AttributionSource);
+    method public void enforceCallingPid();
   }
 
   public final class AutofillOptions implements android.os.Parcelable {
@@ -985,7 +984,7 @@
 package android.graphics {
 
   public final class ImageDecoder implements java.lang.AutoCloseable {
-    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
+    method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, @NonNull java.io.InputStream, int);
   }
 
   public final class Rect implements android.os.Parcelable {
@@ -1607,10 +1606,6 @@
     method public void setIncludeTestInterfaces(boolean);
   }
 
-  public final class IpSecManager {
-    field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
-  }
-
   public class NetworkPolicyManager {
     method public boolean getRestrictBackground();
     method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
@@ -1627,13 +1622,6 @@
     method @Nullable public byte[] getWatchlistConfigHash();
   }
 
-  public class TrafficStats {
-    method public static long getLoopbackRxBytes();
-    method public static long getLoopbackRxPackets();
-    method public static long getLoopbackTxBytes();
-    method public static long getLoopbackTxPackets();
-  }
-
 }
 
 package android.os {
@@ -2522,7 +2510,6 @@
     method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
     method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily();
     method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
     method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
@@ -2804,6 +2791,10 @@
     field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800
   }
 
+  public interface OnBackInvokedDispatcher {
+    field public static final long DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME = 195946584L; // 0xbade858L
+  }
+
   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface RemotableViewMethod {
     method public abstract String asyncImpl() default "";
   }
@@ -2820,7 +2811,7 @@
     method public void setView(@NonNull android.view.View, @NonNull android.view.WindowManager.LayoutParams);
   }
 
-  @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback android.view.OnBackInvokedDispatcherOwner {
+  @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
     method public android.view.View getTooltipView();
     method public boolean isAutofilled();
     method public static boolean isDefaultFocusHighlightEnabled();
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 5649c5f..a5526bc 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -160,7 +160,6 @@
 filegroup {
     name: "framework-services-net-module-wifi-shared-srcs",
     srcs: [
-        "android/net/DhcpResults.java",
         "android/util/LocalLog.java",
     ],
 }
@@ -176,6 +175,18 @@
         "com/android/internal/util/IndentingPrintWriter.java",
         "com/android/internal/util/MessageUtils.java",
         "com/android/internal/util/WakeupMessage.java",
+        // TODO: delete as soon as NetworkStatsFactory stops using
+        "com/android/internal/util/ProcFileReader.java",
+    ],
+}
+
+// keep these files in sync with the packages/modules/Connectivity jarjar-rules.txt for
+// the connectivity module.
+filegroup {
+    name: "framework-connectivity-api-shared-srcs",
+    srcs: [
+        "android/util/IndentingPrintWriter.java",
+        "com/android/internal/util/FileRotator.java",
     ],
 }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 42d2d28..50473f1 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -3120,6 +3120,33 @@
         }
     }
 
+    /**
+     * Sets the system settings values that control the scaling factor for animations. The scale
+     * controls the animation playback speed for animations that respect these settings. Animations
+     * that do not respect the settings values will not be affected by this function. A lower scale
+     * value results in a faster speed. A value of <code>0</code> disables animations entirely. When
+     * animations are disabled services receive window change events more quickly which can reduce
+     * the potential by confusion by reducing the time during which windows are in transition.
+     *
+     * @see AccessibilityEvent#TYPE_WINDOWS_CHANGED
+     * @see AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
+     * @see android.provider.Settings.Global#WINDOW_ANIMATION_SCALE
+     * @see android.provider.Settings.Global#TRANSITION_ANIMATION_SCALE
+     * @see android.provider.Settings.Global#ANIMATOR_DURATION_SCALE
+     * @param scale The scaling factor for all animations.
+     */
+    public void setAnimationScale(float scale) {
+        final IAccessibilityServiceConnection connection =
+                AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId);
+        if (connection != null) {
+            try {
+                connection.setAnimationScale(scale);
+            } catch (RemoteException re) {
+                throw new RuntimeException(re);
+            }
+        }
+    }
+
     private static class AccessibilityContext extends ContextWrapper {
         private final int mConnectionId;
 
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 2cc15b4..0d6b199 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -144,4 +144,6 @@
     void onDoubleTap(int displayId);
 
     void onDoubleTapAndHold(int displayId);
+
+    void setAnimationScale(float scale);
 }
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index eb525d3..a8ff36a 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -16,6 +16,7 @@
 
 package android.animation;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo.Config;
@@ -535,7 +536,7 @@
          * @param animation The started animation.
          * @param isReverse Whether the animation is playing in reverse.
          */
-        default void onAnimationStart(Animator animation, boolean isReverse) {
+        default void onAnimationStart(@NonNull Animator animation, boolean isReverse) {
             onAnimationStart(animation);
         }
 
@@ -551,7 +552,7 @@
          * @param animation The animation which reached its end.
          * @param isReverse Whether the animation is playing in reverse.
          */
-        default void onAnimationEnd(Animator animation, boolean isReverse) {
+        default void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
             onAnimationEnd(animation);
         }
 
@@ -560,7 +561,7 @@
          *
          * @param animation The started animation.
          */
-        void onAnimationStart(Animator animation);
+        void onAnimationStart(@NonNull Animator animation);
 
         /**
          * <p>Notifies the end of the animation. This callback is not invoked
@@ -568,7 +569,7 @@
          *
          * @param animation The animation which reached its end.
          */
-        void onAnimationEnd(Animator animation);
+        void onAnimationEnd(@NonNull Animator animation);
 
         /**
          * <p>Notifies the cancellation of the animation. This callback is not invoked
@@ -576,14 +577,14 @@
          *
          * @param animation The animation which was canceled.
          */
-        void onAnimationCancel(Animator animation);
+        void onAnimationCancel(@NonNull Animator animation);
 
         /**
          * <p>Notifies the repetition of the animation.</p>
          *
          * @param animation The animation which was repeated.
          */
-        void onAnimationRepeat(Animator animation);
+        void onAnimationRepeat(@NonNull Animator animation);
     }
 
     /**
@@ -599,7 +600,7 @@
          * @param animation The animaton being paused.
          * @see #pause()
          */
-        void onAnimationPause(Animator animation);
+        void onAnimationPause(@NonNull Animator animation);
 
         /**
          * <p>Notifies that the animation was resumed, after being
@@ -608,7 +609,7 @@
          * @param animation The animation being resumed.
          * @see #resume()
          */
-        void onAnimationResume(Animator animation);
+        void onAnimationResume(@NonNull Animator animation);
     }
 
     /**
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 3cbae99..06b424b 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -18,6 +18,7 @@
 
 import android.annotation.CallSuper;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -1626,7 +1627,7 @@
          *
          * @param animation The animation which was repeated.
          */
-        void onAnimationUpdate(ValueAnimator animation);
+        void onAnimationUpdate(@NonNull ValueAnimator animation);
 
     }
 
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 530666b..e022700 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -115,6 +115,7 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.OnBackInvokedCallback;
 import android.view.OnBackInvokedDispatcher;
 import android.view.OnBackInvokedDispatcherOwner;
 import android.view.RemoteAnimationDefinition;
@@ -144,6 +145,7 @@
 import android.widget.Toast;
 import android.widget.Toolbar;
 import android.window.SplashScreen;
+import android.window.WindowOnBackInvokedDispatcher;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -791,6 +793,7 @@
     private static final int LOG_AM_ON_ACTIVITY_RESULT_CALLED = 30062;
     private static final int LOG_AM_ON_TOP_RESUMED_GAINED_CALLED = 30064;
     private static final int LOG_AM_ON_TOP_RESUMED_LOST_CALLED = 30065;
+    private OnBackInvokedCallback mDefaultBackCallback;
 
     /**
      * After {@link Build.VERSION_CODES#TIRAMISU},
@@ -1617,7 +1620,16 @@
         }
         mRestoredFromBundle = savedInstanceState != null;
         mCalled = true;
-
+        if (!WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+            // Add onBackPressed as default back behavior.
+            mDefaultBackCallback = new OnBackInvokedCallback() {
+                @Override
+                public void onBackInvoked() {
+                    navigateBack();
+                }
+            };
+            getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
+        }
     }
 
     /**
@@ -2653,6 +2665,10 @@
         if (mUiTranslationController != null) {
             mUiTranslationController.onActivityDestroyed();
         }
+
+        if (mDefaultBackCallback != null) {
+            getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback);
+        }
     }
 
     /**
@@ -3773,10 +3789,13 @@
      * @see KeyEvent
      */
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (getApplicationInfo().targetSdkVersion
-                >= Build.VERSION_CODES.ECLAIR) {
-            if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
-                    && !event.isCanceled()) {
+        int sdkVersion = getApplicationInfo().targetSdkVersion;
+        if (sdkVersion >= Build.VERSION_CODES.ECLAIR) {
+            if (keyCode == KeyEvent.KEYCODE_BACK
+                    && event.isTracking()
+                    && !event.isCanceled()
+                    && mDefaultBackCallback == null) {
+                // Using legacy back handling.
                 onBackPressed();
                 return true;
             }
@@ -3841,6 +3860,10 @@
         if (!fragmentManager.isStateSaved() && fragmentManager.popBackStackImmediate()) {
             return;
         }
+        navigateBack();
+    }
+
+    private void navigateBack() {
         if (!isTaskRoot()) {
             // If the activity is not the root of the task, allow finish to proceed normally.
             finishAfterTransition();
@@ -5503,6 +5526,17 @@
      */
     public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
             IBinder permissionToken, boolean ignoreTargetSecurity, int userId) {
+        startActivityAsCaller(intent, options, permissionToken, ignoreTargetSecurity, userId, -1);
+    }
+
+    /**
+     * @see #startActivityAsCaller(Intent, Bundle, IBinder, boolean, int)
+     * @param requestCode The request code used for returning a result or -1 if no result should be
+     *                    returned.
+     * @hide
+     */
+    public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
+            IBinder permissionToken, boolean ignoreTargetSecurity, int userId, int requestCode) {
         if (mParent != null) {
             throw new RuntimeException("Can't be called from a child");
         }
@@ -5510,11 +5544,11 @@
         Instrumentation.ActivityResult ar =
                 mInstrumentation.execStartActivityAsCaller(
                         this, mMainThread.getApplicationThread(), mToken, this,
-                        intent, -1, options, permissionToken, ignoreTargetSecurity, userId);
+                        intent, requestCode, options, permissionToken, ignoreTargetSecurity,
+                        userId);
         if (ar != null) {
             mMainThread.sendActivityResult(
-                mToken, mEmbeddedID, -1, ar.getResultCode(),
-                ar.getResultData());
+                    mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
         }
         cancelInputsAndStartExitTransition(options);
     }
@@ -6139,6 +6173,10 @@
      * you to specify a custom animation even when starting an activity from
      * outside the context of the current top activity.
      *
+     * <p>Af of {@link android.os.Build.VERSION_CODES#S} application can only specify
+     * a transition animation when the transition happens within the same task. System
+     * default animation is used for cross-task transition animations.
+     *
      * @param enterAnim A resource ID of the animation resource to use for
      * the incoming activity.  Use 0 for no animation.
      * @param exitAnim A resource ID of the animation resource to use for
@@ -7171,7 +7209,7 @@
             // Handle special cases
             switch (args[0]) {
                 case "--autofill":
-                    getAutofillClientController().dumpAutofillManager(prefix, writer);
+                    dumpAutofillManager(prefix, writer, args);
                     return;
                 case "--contentcapture":
                     dumpContentCaptureManager(prefix, writer);
@@ -7239,10 +7277,6 @@
 
         mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
 
-        getAutofillClientController().dumpAutofillManager(prefix, writer);
-        dumpContentCaptureManager(prefix, writer);
-        dumpUiTranslation(prefix, writer);
-
         ResourcesManager.getInstance().dump(prefix, writer);
 
         if (mDumpableContainer != null) {
@@ -7250,21 +7284,26 @@
         }
     }
 
-    void dumpContentCaptureManager(String prefix, PrintWriter writer) {
-        final ContentCaptureManager cm = getContentCaptureManager();
-        if (cm != null) {
-            cm.dump(prefix, writer);
-        } else {
-            writer.print(prefix); writer.println("No ContentCaptureManager");
-        }
+    private void dumpContentCaptureManager(String prefix, PrintWriter writer) {
+        getContentCaptureManager();
+        dumpLegacyDumpable(prefix, writer, ContentCaptureManager.DUMPABLE_NAME, /* args= */ null);
     }
 
-    void dumpUiTranslation(String prefix, PrintWriter writer) {
-        if (mUiTranslationController != null) {
-            mUiTranslationController.dump(prefix, writer);
-        } else {
-            writer.print(prefix); writer.println("No UiTranslationController");
+    private void dumpUiTranslation(String prefix, PrintWriter writer) {
+        dumpLegacyDumpable(prefix, writer, UiTranslationController.DUMPABLE_NAME, /* args= */ null);
+    }
+
+    private void dumpAutofillManager(String prefix, PrintWriter writer, String[] args) {
+        dumpLegacyDumpable(prefix, writer, AutofillClientController.DUMPABLE_NAME, args);
+    }
+
+    private void dumpLegacyDumpable(@NonNull String prefix, @NonNull PrintWriter writer,
+            @NonNull String dumpableName, @Nullable String[] args) {
+        if (mDumpableContainer == null) {
+            writer.print(prefix); writer.print("no "); writer.println(dumpableName);
+            return;
         }
+        mDumpableContainer.dumpOneDumpable(prefix, writer, dumpableName, args);
     }
 
     /**
@@ -8742,17 +8781,15 @@
      * Returns the {@link OnBackInvokedDispatcher} instance associated with the window that this
      * activity is attached to.
      *
-     * Returns null if the activity is not attached to a window with a decor.
+     * @throws IllegalStateException if this Activity is not visual.
      */
-    @Nullable
+    @NonNull
     @Override
     public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
-        if (mWindow != null) {
-            View decorView = mWindow.getDecorView();
-            if (decorView != null) {
-                return decorView.getOnBackInvokedDispatcher();
-            }
+        if (mWindow == null) {
+            throw new IllegalStateException("OnBackInvokedDispatcher are not available on "
+                    + "non-visual activities");
         }
-        return null;
+        return ((OnBackInvokedDispatcherOwner) mWindow).getOnBackInvokedDispatcher();
     }
 }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index fdf37f6..0d1bc05 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2363,11 +2363,11 @@
             Manifest.permission.USE_BIOMETRIC,
             Manifest.permission.ACTIVITY_RECOGNITION,
             Manifest.permission.SMS_FINANCIAL_TRANSACTIONS,
-            null,
+            Manifest.permission.READ_MEDIA_AUDIO,
             null, // no permission for OP_WRITE_MEDIA_AUDIO
-            null,
+            Manifest.permission.READ_MEDIA_VIDEO,
             null, // no permission for OP_WRITE_MEDIA_VIDEO
-            null,
+            Manifest.permission.READ_MEDIA_IMAGE,
             null, // no permission for OP_WRITE_MEDIA_IMAGES
             null, // no permission for OP_LEGACY_STORAGE
             null, // no permission for OP_ACCESS_ACCESSIBILITY
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 9039bbd..60e22f4 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -156,6 +156,12 @@
     public static final int REASON_OTHER = 13;
 
     /**
+     * Application process was killed by App Freezer, for example, because it receives
+     * sync binder transactions while being frozen.
+     */
+    public static final int REASON_FREEZER = 14;
+
+    /**
      * Application process kills subreason is unknown.
      *
      * For internal use only.
@@ -487,6 +493,7 @@
         REASON_USER_STOPPED,
         REASON_DEPENDENCY_DIED,
         REASON_OTHER,
+        REASON_FREEZER,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Reason {}
@@ -1138,6 +1145,8 @@
                 return "DEPENDENCY DIED";
             case REASON_OTHER:
                 return "OTHER KILLS BY SYSTEM";
+            case REASON_FREEZER:
+                return "FREEZER";
             default:
                 return "UNKNOWN";
         }
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index a7fb83b..2084775 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -52,6 +52,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.OnBackInvokedCallback;
 import android.view.OnBackInvokedDispatcher;
 import android.view.OnBackInvokedDispatcherOwner;
 import android.view.SearchEvent;
@@ -62,6 +63,7 @@
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
+import android.window.WindowOnBackInvokedDispatcher;
 
 import com.android.internal.R;
 import com.android.internal.app.WindowDecorActionBar;
@@ -156,6 +158,7 @@
 
     /** A {@link Runnable} to run instead of dismissing when {@link #dismiss()} is called. */
     private Runnable mDismissOverride;
+    private OnBackInvokedCallback mDefaultBackCallback;
 
     /**
      * Creates a dialog window that uses the default dialog theme.
@@ -453,6 +456,16 @@
      */
     protected void onStart() {
         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
+        if (mContext != null && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+            // Add onBackPressed as default back behavior.
+            mDefaultBackCallback = new OnBackInvokedCallback() {
+                @Override
+                public void onBackInvoked() {
+                    onBackPressed();
+                }
+            };
+            getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
+        }
     }
 
     /**
@@ -460,6 +473,9 @@
      */
     protected void onStop() {
         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
+        if (mDefaultBackCallback != null) {
+            getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback);
+        }
     }
 
     private static final String DIALOG_SHOWING_TAG = "android:dialogShowing";
@@ -685,7 +701,8 @@
     public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
         if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
                 && event.isTracking()
-                && !event.isCanceled()) {
+                && !event.isCanceled()
+                && WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
             onBackPressed();
             return true;
         }
@@ -1449,15 +1466,9 @@
      *
      * Returns null if the dialog is not attached to a window with a decor.
      */
-    @Nullable
+    @NonNull
     @Override
     public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
-        if (mWindow != null) {
-            View decorView = mWindow.getDecorView();
-            if (decorView != null) {
-                return decorView.getOnBackInvokedDispatcher();
-            }
-        }
-        return null;
+        return ((OnBackInvokedDispatcherOwner) mWindow).getOnBackInvokedDispatcher();
     }
 }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index e4ef12c..7c48a57 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -679,6 +679,10 @@
      */
     boolean isAppFreezerSupported();
 
+    /**
+     * Return whether the app freezer is enabled (true) or not (false) by this system.
+     */
+    boolean isAppFreezerEnabled();
 
     /**
      * Kills uid with the reason of permission change.
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 0801b24..c5add66 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -130,6 +130,9 @@
             in ProfilerInfo profilerInfo, in Bundle options, int userId);
     int startAssistantActivity(in String callingPackage, in String callingFeatureId, int callingPid,
             int callingUid, in Intent intent, in String resolvedType, in Bundle options, int userId);
+    int startActivityFromGameSession(IApplicationThread caller, in String callingPackage,
+            in String callingFeatureId, int callingPid, int callingUid, in Intent intent,
+            int taskId, int userId);
     void startRecentsActivity(in Intent intent, in long eventTime,
             in IRecentsAnimationRunner recentsAnimationRunner);
     int startActivityFromRecents(int taskId, in Bundle options);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index eb4585d..a74438a 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -376,14 +376,16 @@
             Debug.stopMethodTracing();
         }
     }
-    
+
     /**
-     * Force the global system in or out of touch mode.  This can be used if
-     * your instrumentation relies on the UI being in one more or the other
-     * when it starts.
-     * 
-     * @param inTouch Set to true to be in touch mode, false to be in
-     * focus mode.
+     * Force the global system in or out of touch mode. This can be used if your
+     * instrumentation relies on the UI being in one more or the other when it starts.
+     *
+     * <p><b>Note:</b> Starting from Android {@link Build.VERSION_CODES#TIRAMISU}, this method
+     * will only have an effect if the calling process is also the focused window owner or has
+     * {@link android.permission#MODIFY_TOUCH_MODE_STATE} permission granted.
+     *
+     * @param inTouch Set to true to be in touch mode, false to be in focus mode.
      */
     public void setInTouchMode(boolean inTouch) {
         try {
@@ -393,11 +395,11 @@
             // Shouldn't happen!
         }
     }
-    
+
     /**
      * Schedule a callback for when the application's main thread goes idle
      * (has no more events to process).
-     * 
+     *
      * @param recipient Called the next time the thread's message queue is
      *                  idle.
      */
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 8fcb07f..da1ba52 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -180,6 +180,8 @@
     public static final int NAVIGATION_HINT_BACK_ALT      = 1 << 0;
     /** @hide */
     public static final int NAVIGATION_HINT_IME_SHOWN     = 1 << 1;
+    /** @hide */
+    public static final int NAVIGATION_HINT_IME_SWITCHER_SHOWN = 1 << 2;
 
     /** @hide */
     public static final int WINDOW_STATUS_BAR = 1;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 79180cb..f5f2fe0 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -48,7 +48,6 @@
 import android.app.trust.TrustManager;
 import android.app.usage.IStorageStatsManager;
 import android.app.usage.IUsageStatsManager;
-import android.app.usage.NetworkStatsManager;
 import android.app.usage.StorageStatsManager;
 import android.app.usage.UsageStatsManager;
 import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager;
@@ -139,12 +138,9 @@
 import android.net.ConnectivityFrameworkInitializerTiramisu;
 import android.net.EthernetManager;
 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;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
 import android.net.NetworkWatchlistManager;
@@ -441,15 +437,6 @@
                 return new VcnManager(ctx, service);
             }});
 
-        registerService(Context.IPSEC_SERVICE, IpSecManager.class,
-                new CachedServiceFetcher<IpSecManager>() {
-            @Override
-            public IpSecManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getService(Context.IPSEC_SERVICE);
-                IIpSecService service = IIpSecService.Stub.asInterface(b);
-                return new IpSecManager(ctx, service);
-            }});
-
         registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
                 new StaticServiceFetcher<CountryDetector>() {
             @Override
@@ -1024,17 +1011,6 @@
                 return new UsageStatsManager(ctx.getOuterContext(), service);
             }});
 
-        registerService(Context.NETWORK_STATS_SERVICE, NetworkStatsManager.class,
-                new CachedServiceFetcher<NetworkStatsManager>() {
-            @Override
-            public NetworkStatsManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                // 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,
                 new StaticServiceFetcher<PersistentDataBlockManager>() {
             @Override
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 00903a8..b41b5f00 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -780,6 +780,33 @@
     }
 
     /**
+     * Sets the system settings values that control the scaling factor for animations. The scale
+     * controls the animation playback speed for animations that respect these settings. Animations
+     * that do not respect the settings values will not be affected by this function. A lower scale
+     * value results in a faster speed. A value of <code>0</code> disables animations entirely. When
+     * animations are disabled services receive window change events more quickly which can reduce
+     * the potential by confusion by reducing the time during which windows are in transition.
+     *
+     * @see AccessibilityEvent#TYPE_WINDOWS_CHANGED
+     * @see AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
+     * @see android.provider.Settings.Global#WINDOW_ANIMATION_SCALE
+     * @see android.provider.Settings.Global#TRANSITION_ANIMATION_SCALE
+     * @see android.provider.Settings.Global#ANIMATOR_DURATION_SCALE
+     * @param scale The scaling factor for all animations.
+     */
+    public void setAnimationScale(float scale) {
+        final IAccessibilityServiceConnection connection =
+                AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+        if (connection != null) {
+            try {
+                connection.setAnimationScale(scale);
+            } catch (RemoteException re) {
+                throw new RuntimeException(re);
+            }
+        }
+    }
+
+    /**
      * A request for WindowManagerService to wait until all animations have completed and input
      * information has been sent from WindowManager to native InputManager.
      *
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 82cdf6f..108412d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -56,9 +56,11 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.net.PrivateDnsConnectivityChecker;
 import android.net.ProxyInfo;
 import android.net.Uri;
+import android.net.wifi.WifiSsid;
 import android.nfc.NfcAdapter;
 import android.os.Binder;
 import android.os.Build;
@@ -111,6 +113,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
+import java.nio.charset.StandardCharsets;
 import java.security.KeyFactory;
 import java.security.KeyPair;
 import java.security.NoSuchAlgorithmException;
@@ -463,7 +466,9 @@
      * <li>{@link #setUserControlDisabledPackages(ComponentName, List)}</li>
      * <li>{@link #getUserControlDisabledPackages(ComponentName)}</li>
      * <li>{@link #setOrganizationName(ComponentName, CharSequence)}</li>
+     * <li>{@link #getOrganizationName(ComponentName)} </li>
      * <li>{@link #setShortSupportMessage(ComponentName, CharSequence)}</li>
+     * <li>{@link #getShortSupportMessage(ComponentName)}</li>
      * <li>{@link #isBackupServiceEnabled(ComponentName)}</li>
      * <li>{@link #setBackupServiceEnabled(ComponentName, boolean)}</li>
      * <li>{@link #isLockTaskPermitted(String)}</li>
@@ -476,7 +481,9 @@
      *     <li>{@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS}</li>
      *     <li>{@link #LOCK_TASK_FEATURE_NOTIFICATIONS}</li>
      * </ul>
+     * <li>{@link #getLockTaskFeatures(ComponentName)}</li>
      * <li>{@link #setLockTaskPackages(ComponentName, String[])}</li>
+     * <li>{@link #getLockTaskPackages(ComponentName)}</li>
      * <li>{@link #addPersistentPreferredActivity(ComponentName, IntentFilter, ComponentName)}</li>
      * <li>{@link #clearPackagePersistentPreferredActivities(ComponentName, String)} </li>
      * <li>{@link #wipeData(int)}</li>
@@ -487,6 +494,10 @@
      * {@link #PERMISSION_GRANT_STATE_GRANTED}, {@link #PERMISSION_GRANT_STATE_DENIED}, or
      * {@link #PERMISSION_GRANT_STATE_DEFAULT} and can <b>only</b> be applied to the device admin
      * app (otherwise a {@link SecurityException} will be thrown)</li>
+     * <li>{@link #getPermissionGrantState(ComponentName, String, String)}, where
+     * {@link permission#READ_PHONE_STATE} is the <b>only</b> permission that can be
+     * used and device admin app is the only package that can be used to retrieve the permission
+     * permission grant state for (otherwise a {@link SecurityException} will be thrown)</li>
      * <li>{@link #addUserRestriction(ComponentName, String)}, where the following user restrictions
      * are permitted (otherwise a {@link SecurityException} will be thrown):</li>
      * <ul>
@@ -497,7 +508,17 @@
      *     <li>{@link UserManager#DISALLOW_CONFIG_DATE_TIME}</li>
      *     <li>{@link UserManager#DISALLOW_OUTGOING_CALLS}</li>
      * </ul>
-     * <li>{@link #clearUserRestriction(ComponentName, String)}</li>
+     * <li>{@link #getUserRestrictions(ComponentName)}</li>
+     * <li>{@link #clearUserRestriction(ComponentName, String)}, where the following user
+     * restrictions are permitted (otherwise a {@link SecurityException} will be thrown):</li>
+     * <ul>
+     *     <li>{@link UserManager#DISALLOW_ADD_USER}</li>
+     *     <li>{@link UserManager#DISALLOW_DEBUGGING_FEATURES}</li>
+     *     <li>{@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES}</li>
+     *     <li>{@link UserManager#DISALLOW_SAFE_BOOT}</li>
+     *     <li>{@link UserManager#DISALLOW_CONFIG_DATE_TIME}</li>
+     *     <li>{@link UserManager#DISALLOW_OUTGOING_CALLS}</li>
+     * </ul>
      * </ul>
      *
      * @hide
@@ -1330,7 +1351,10 @@
      *
      * <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE} or
      * {@link #ACTION_PROVISION_MANAGED_DEVICE}
+     *
+     * @deprecated Logo customization is no longer supported in the provisioning flow.
      */
+    @Deprecated
     public static final String EXTRA_PROVISIONING_LOGO_URI =
             "android.app.extra.PROVISIONING_LOGO_URI";
 
@@ -3254,6 +3278,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final int DEVICE_OWNER_TYPE_DEFAULT = 0;
 
     /**
@@ -3261,6 +3286,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final int DEVICE_OWNER_TYPE_FINANCED = 1;
 
     /**
@@ -14906,10 +14932,14 @@
                     mService.setSsidAllowlist(new ArrayList<>());
                 } else {
                     int policyType = policy.getPolicyType();
+                    List<String> ssidList = new ArrayList<>();
+                    for (WifiSsid ssid : policy.getSsids()) {
+                        ssidList.add(new String(ssid.getBytes(), StandardCharsets.UTF_8));
+                    }
                     if (policyType == WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST) {
-                        mService.setSsidAllowlist(new ArrayList<>(policy.getSsids()));
+                        mService.setSsidAllowlist(ssidList);
                     } else {
-                        mService.setSsidDenylist(new ArrayList<>(policy.getSsids()));
+                        mService.setSsidDenylist(ssidList);
                     }
                 }
             } catch (RemoteException e) {
@@ -14935,11 +14965,23 @@
         try {
             List<String> allowlist = mService.getSsidAllowlist();
             if (!allowlist.isEmpty()) {
-                return WifiSsidPolicy.createAllowlistPolicy(new ArraySet<>(allowlist));
+                List<WifiSsid> wifiSsidAllowlist = new ArrayList<>();
+                for (String ssid : allowlist) {
+                    wifiSsidAllowlist.add(
+                            WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8)));
+                }
+                return new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST,
+                        new ArraySet<>(wifiSsidAllowlist));
             }
             List<String> denylist = mService.getSsidDenylist();
             if (!denylist.isEmpty()) {
-                return WifiSsidPolicy.createDenylistPolicy(new ArraySet<>(denylist));
+                List<WifiSsid> wifiSsidDenylist = new ArrayList<>();
+                for (String ssid : denylist) {
+                    wifiSsidDenylist.add(
+                            WifiSsid.fromBytes(ssid.getBytes(StandardCharsets.UTF_8)));
+                }
+                return new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST,
+                        new ArraySet<>(wifiSsidDenylist));
             }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -15203,6 +15245,66 @@
     }
 
     /**
+     * Similar to {@link #getDrawable(String, String, String, Callable)} but returns an
+     * {@link Icon} instead of a {@link Drawable}.
+     *
+     * @param drawableId The drawable ID to get the updated resource for.
+     * @param drawableStyle The drawable style to use.
+     * @param drawableSource The source for the caller.
+     * @param defaultIcon Returned if no updated drawable was set for the provided params.
+     */
+    @Nullable
+    public Icon getDrawableAsIcon(
+            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
+            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
+            @NonNull @DevicePolicyResources.UpdatableDrawableSource String drawableSource,
+            @Nullable Icon defaultIcon) {
+        Objects.requireNonNull(drawableId, "drawableId can't be null");
+        Objects.requireNonNull(drawableStyle, "drawableStyle can't be null");
+        Objects.requireNonNull(drawableSource, "drawableSource can't be null");
+        Objects.requireNonNull(defaultIcon, "defaultIcon can't be null");
+
+        if (Drawables.UNDEFINED.equals(drawableId)) {
+            return defaultIcon;
+        }
+        if (mService != null) {
+            try {
+                ParcelableResource resource = mService.getDrawable(
+                        drawableId, drawableStyle, drawableSource);
+                if (resource == null) {
+                    return defaultIcon;
+                }
+                return Icon.createWithResource(resource.getPackageName(), resource.getResourceId());
+            } catch (RemoteException e) {
+                Log.e(
+                        TAG,
+                        "Error getting the updated drawable from DevicePolicyManagerService.",
+                        e);
+                return defaultIcon;
+            }
+        }
+        return defaultIcon;
+    }
+
+    /**
+     * Similar to {@link #getDrawable(String, String, Callable)} but returns an {@link Icon}
+     * instead of a {@link Drawable}.
+     *
+     * @param drawableId The drawable ID to get the updated resource for.
+     * @param drawableStyle The drawable style to use.
+     * @param defaultIcon Returned if no updated drawable was set for the provided params.
+     */
+    @Nullable
+    public Icon getDrawableAsIcon(
+            @NonNull @DevicePolicyResources.UpdatableDrawableId String drawableId,
+            @NonNull @DevicePolicyResources.UpdatableDrawableStyle String drawableStyle,
+            @Nullable Icon defaultIcon) {
+        return getDrawableAsIcon(
+                drawableId, drawableStyle, Drawables.Source.UNDEFINED, defaultIcon);
+    }
+
+
+    /**
      * For each {@link DevicePolicyStringResource} item in {@code strings}, it updates the string
      * resource for {@link DevicePolicyStringResource#getStringId()} to the string with ID
      * {@code callingPackageResourceId} (see {@link DevicePolicyResources.Strings}), meaning any
@@ -15364,4 +15466,45 @@
         }
         return ParcelableResource.loadDefaultString(defaultStringLoader);
     }
+
+    /**
+     * Returns a boolean for whether the DPC has been downloaded during provisioning.
+     *
+     * <p>If true is returned, then any attempts to begin setup again should result in factory reset
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    public boolean isDpcDownloaded() {
+        throwIfParentInstance("isDpcDownloaded");
+        if (mService != null) {
+            try {
+                return mService.isDpcDownloaded();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Use to indicate that the DPC has or has not been downloaded during provisioning.
+     *
+     * @param downloaded {@code true} if the dpc has been downloaded during provisioning. false otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+    public void setDpcDownloaded(boolean downloaded) {
+        throwIfParentInstance("setDpcDownloaded");
+        if (mService != null) {
+            try {
+                mService.setDpcDownloaded(downloaded);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index ac39cb4..7f2e5fd 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -58,6 +58,10 @@
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_GENERIC_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL;
 import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE;
 import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE;
 import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_WORK_MESSAGE;
@@ -512,7 +516,11 @@
             WORK_PROFILE_DEFAULT_APPS_TITLE, HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE,
             BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE, BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
             BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE, FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
-            LOCATION_AUTO_GRANTED_MESSAGE
+            LOCATION_AUTO_GRANTED_MESSAGE,
+
+            // Dialer Strings
+            NOTIFICATION_INCOMING_WORK_CALL_TITLE, NOTIFICATION_ONGOING_WORK_CALL_TITLE,
+            NOTIFICATION_MISSED_WORK_CALL_TITLE, NOTIFICATION_WIFI_WORK_CALL_LABEL,
     })
     public @interface UpdatableStringId {
     }
@@ -709,6 +717,7 @@
             strings.addAll(DocumentsUi.buildStringsSet());
             strings.addAll(MediaProvider.buildStringsSet());
             strings.addAll(PermissionController.buildStringsSet());
+            strings.addAll(Dialer.buildStringsSet());
             return strings;
         }
 
@@ -2934,5 +2943,54 @@
                 return strings;
             }
         }
+
+        /**
+         * Class containing the identifiers used to update device management-related system strings
+         * in the Dialer app.
+         */
+        public static final class Dialer {
+
+            private Dialer() {
+            }
+
+            private static final String PREFIX = "Dialer.";
+
+            /**
+             * The title of the in-call notification for an incoming work call.
+             */
+            public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE =
+                    PREFIX + "NOTIFICATION_INCOMING_WORK_CALL_TITLE";
+
+            /**
+             * The title of the in-call notification for an ongoing work call.
+             */
+            public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE =
+                    PREFIX + "NOTIFICATION_ONGOING_WORK_CALL_TITLE";
+
+            /**
+             * Missed call notification label, used when there's exactly one missed call from work
+             * contact.
+             */
+            public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE =
+                    PREFIX + "NOTIFICATION_MISSED_WORK_CALL_TITLE";
+
+            /**
+             * Label for notification indicating that call is being made over wifi.
+             */
+            public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL =
+                    PREFIX + "NOTIFICATION_WIFI_WORK_CALL_LABEL";
+
+            /**
+             * @hide
+             */
+            static Set<String> buildStringsSet() {
+                Set<String> strings = new HashSet<>();
+                strings.add(NOTIFICATION_INCOMING_WORK_CALL_TITLE);
+                strings.add(NOTIFICATION_ONGOING_WORK_CALL_TITLE);
+                strings.add(NOTIFICATION_MISSED_WORK_CALL_TITLE);
+                strings.add(NOTIFICATION_WIFI_WORK_CALL_LABEL);
+                return strings;
+            }
+        }
     }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a7a51f8..0e1caca 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -555,6 +555,9 @@
     void resetDrawables(in String[] drawableIds);
     ParcelableResource getDrawable(String drawableId, String drawableStyle, String drawableSource);
 
+    boolean isDpcDownloaded();
+    void setDpcDownloaded(boolean downloaded);
+
     void setStrings(in List<DevicePolicyStringResource> strings);
     void resetStrings(in String[] stringIds);
     ParcelableResource getString(String stringId);
diff --git a/core/java/android/app/admin/WifiSsidPolicy.java b/core/java/android/app/admin/WifiSsidPolicy.java
index 3715017..e918075 100644
--- a/core/java/android/app/admin/WifiSsidPolicy.java
+++ b/core/java/android/app/admin/WifiSsidPolicy.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.net.wifi.WifiSsid;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
@@ -70,50 +71,37 @@
     public @interface WifiSsidPolicyType {}
 
     private @WifiSsidPolicyType int mPolicyType;
-    private ArraySet<String> mSsids;
+    private ArraySet<WifiSsid> mSsids;
 
-    private WifiSsidPolicy(@WifiSsidPolicyType int policyType, @NonNull Set<String> ssids) {
+    /**
+     * Create the Wi-Fi SSID Policy.
+     *
+     * @param policyType indicate whether the policy is an allowlist or a denylist
+     * @param ssids set of {@link WifiSsid}
+     * @throws IllegalArgumentException if the input ssids set is empty or the policyType is invalid
+     */
+    public WifiSsidPolicy(@WifiSsidPolicyType int policyType, @NonNull Set<WifiSsid> ssids) {
+        if (ssids.isEmpty()) {
+            throw new IllegalArgumentException("SSID list cannot be empty");
+        }
+        if (policyType != WIFI_SSID_POLICY_TYPE_ALLOWLIST
+                && policyType != WIFI_SSID_POLICY_TYPE_DENYLIST) {
+            throw new IllegalArgumentException("Invalid policy type");
+        }
         mPolicyType = policyType;
         mSsids = new ArraySet<>(ssids);
     }
 
     private WifiSsidPolicy(Parcel in) {
         mPolicyType = in.readInt();
-        mSsids = (ArraySet<String>) in.readArraySet(null);
-    }
-    /**
-     * Create the allowlist Wi-Fi SSID Policy.
-     *
-     * @param ssids allowlist of SSIDs in UTF-8 without double quotes format
-     * @throws IllegalArgumentException if the input ssids list is empty
-     */
-    @NonNull
-    public static WifiSsidPolicy createAllowlistPolicy(@NonNull Set<String> ssids) {
-        if (ssids.isEmpty()) {
-            throw new IllegalArgumentException("SSID list cannot be empty");
-        }
-        return new WifiSsidPolicy(WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids);
+        mSsids = (ArraySet<WifiSsid>) in.readArraySet(null);
     }
 
     /**
-     * Create the denylist Wi-Fi SSID Policy.
-     *
-     * @param ssids denylist of SSIDs in UTF-8 without double quotes format
-     * @throws IllegalArgumentException if the input ssids list is empty
+     * Returns the set of {@link WifiSsid}
      */
     @NonNull
-    public static WifiSsidPolicy createDenylistPolicy(@NonNull Set<String> ssids) {
-        if (ssids.isEmpty()) {
-            throw new IllegalArgumentException("SSID list cannot be empty");
-        }
-        return new WifiSsidPolicy(WIFI_SSID_POLICY_TYPE_DENYLIST, ssids);
-    }
-
-    /**
-     * Returns the set of SSIDs in UTF-8 without double quotes format.
-     */
-    @NonNull
-    public Set<String> getSsids() {
+    public Set<WifiSsid> getSsids() {
         return mSsids;
     }
 
diff --git a/core/java/android/app/cloudsearch/SearchResult.java b/core/java/android/app/cloudsearch/SearchResult.java
index 060931b..3403ab0 100644
--- a/core/java/android/app/cloudsearch/SearchResult.java
+++ b/core/java/android/app/cloudsearch/SearchResult.java
@@ -76,7 +76,7 @@
     public @interface SearchResultExtraInfoKey {}
     /** This App developer website's domain URL, String value expected. */
     public static final String EXTRAINFO_APP_DOMAIN_URL = "APP_DOMAIN_URL";
-    /** This App result's ICON URL, String value expected. */
+    /** This App icon, android.graphics.drawable.Icon expected. */
     public static final String EXTRAINFO_APP_ICON = "APP_ICON";
     /** This App developer's name, String value expected. */
     public static final String EXTRAINFO_APP_DEVELOPER_NAME = "APP_DEVELOPER_NAME";
@@ -114,7 +114,7 @@
     public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "ACTION_BUTTON_IMAGE";
     /** Web content's URL, String value expected. */
     public static final String EXTRAINFO_WEB_URL = "WEB_URL";
-    /** Web content's domain icon URL, String value expected. */
+    /** Web content's domain icon, android.graphics.drawable.Icon expected. */
     public static final String EXTRAINFO_WEB_ICON = "WEB_ICON";
 
     @NonNull
diff --git a/core/java/android/app/smartspace/SmartspaceUtils.java b/core/java/android/app/smartspace/SmartspaceUtils.java
index f058ffa..4545f43 100644
--- a/core/java/android/app/smartspace/SmartspaceUtils.java
+++ b/core/java/android/app/smartspace/SmartspaceUtils.java
@@ -17,6 +17,8 @@
 package android.app.smartspace;
 
 import android.annotation.Nullable;
+import android.app.smartspace.uitemplatedata.SmartspaceText;
+import android.text.TextUtils;
 
 /**
  * Utilities for Smartspace data.
@@ -28,10 +30,22 @@
     private SmartspaceUtils() {
     }
 
+    /** Returns true if the passed in {@link SmartspaceText} is null or its content is empty. */
+    public static boolean isEmpty(@Nullable SmartspaceText text) {
+        return text == null || TextUtils.isEmpty(text.getText());
+    }
+
+    /** Returns true if the passed-in {@link SmartspaceText}s are equal. */
+    public static boolean isEqual(@Nullable SmartspaceText text1, @Nullable SmartspaceText text2) {
+        if (text1 == null && text2 == null) return true;
+        if (text1 == null || text2 == null) return false;
+        return text1.equals(text2);
+    }
+
     /** Returns true if the passed-in {@link CharSequence}s are equal. */
     public static boolean isEqual(@Nullable CharSequence cs1, @Nullable CharSequence cs2) {
-        if ((cs1 == null && cs2 != null) || (cs1 != null && cs2 == null)) return false;
         if (cs1 == null && cs2 == null) return true;
+        if (cs1 == null || cs2 == null) return false;
         return cs1.toString().contentEquals(cs2);
     }
 }
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java
index c4c4fde..e996056 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java
@@ -23,7 +23,6 @@
 import android.app.smartspace.SmartspaceUtils;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
 
 import java.util.List;
 import java.util.Objects;
@@ -51,15 +50,15 @@
     }
 
     private SmartspaceCarouselUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable CharSequence titleText,
+            @Nullable SmartspaceText titleText,
             @Nullable SmartspaceIcon titleIcon,
-            @Nullable CharSequence subtitleText,
+            @Nullable SmartspaceText subtitleText,
             @Nullable SmartspaceIcon subTitleIcon,
             @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable CharSequence supplementalSubtitleText,
+            @Nullable SmartspaceText supplementalSubtitleText,
             @Nullable SmartspaceIcon supplementalSubtitleIcon,
             @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable CharSequence supplementalAlarmText,
+            @Nullable SmartspaceText supplementalAlarmText,
             @NonNull List<CarouselItem> carouselItems,
             @Nullable SmartspaceTapAction carouselAction) {
         super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
@@ -170,11 +169,11 @@
             if (mCarouselItems.isEmpty()) {
                 throw new IllegalStateException("Carousel data is empty");
             }
+
             return new SmartspaceCarouselUiTemplateData(getTemplateType(), getTitleText(),
-                    getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(),
+                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
                     getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
-                    getSupplementalSubtitleTapAction(), getSupplementalAlarmText(),
-                    mCarouselItems,
+                    getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mCarouselItems,
                     mCarouselAction);
         }
     }
@@ -184,7 +183,7 @@
 
         /** Text which is above the image item. */
         @Nullable
-        private final CharSequence mUpperText;
+        private final SmartspaceText mUpperText;
 
         /** Image item. Can be empty. */
         @Nullable
@@ -192,7 +191,7 @@
 
         /** Text which is under the image item. */
         @Nullable
-        private final CharSequence mLowerText;
+        private final SmartspaceText mLowerText;
 
         /**
          * Tap action for this {@link CarouselItem} instance. {@code mCarouselAction} is used if not
@@ -202,14 +201,14 @@
         private final SmartspaceTapAction mTapAction;
 
         CarouselItem(@NonNull Parcel in) {
-            mUpperText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            mUpperText = in.readTypedObject(SmartspaceText.CREATOR);
             mImage = in.readTypedObject(SmartspaceIcon.CREATOR);
-            mLowerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            mLowerText = in.readTypedObject(SmartspaceText.CREATOR);
             mTapAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
         }
 
-        private CarouselItem(@Nullable CharSequence upperText, @Nullable SmartspaceIcon image,
-                @Nullable CharSequence lowerText, @Nullable SmartspaceTapAction tapAction) {
+        private CarouselItem(@Nullable SmartspaceText upperText, @Nullable SmartspaceIcon image,
+                @Nullable SmartspaceText lowerText, @Nullable SmartspaceTapAction tapAction) {
             mUpperText = upperText;
             mImage = image;
             mLowerText = lowerText;
@@ -217,7 +216,7 @@
         }
 
         @Nullable
-        public CharSequence getUpperText() {
+        public SmartspaceText getUpperText() {
             return mUpperText;
         }
 
@@ -227,7 +226,7 @@
         }
 
         @Nullable
-        public CharSequence getLowerText() {
+        public SmartspaceText getLowerText() {
             return mLowerText;
         }
 
@@ -260,9 +259,9 @@
 
         @Override
         public void writeToParcel(@NonNull Parcel out, int flags) {
-            TextUtils.writeToParcel(mUpperText, out, flags);
+            out.writeTypedObject(mUpperText, flags);
             out.writeTypedObject(mImage, flags);
-            TextUtils.writeToParcel(mLowerText, out, flags);
+            out.writeTypedObject(mLowerText, flags);
             out.writeTypedObject(mTapAction, flags);
         }
 
@@ -300,16 +299,16 @@
         @SystemApi
         public static final class Builder {
 
-            private CharSequence mUpperText;
+            private SmartspaceText mUpperText;
             private SmartspaceIcon mImage;
-            private CharSequence mLowerText;
+            private SmartspaceText mLowerText;
             private SmartspaceTapAction mTapAction;
 
             /**
              * Sets the upper text.
              */
             @NonNull
-            public Builder setUpperText(@Nullable CharSequence upperText) {
+            public Builder setUpperText(@Nullable SmartspaceText upperText) {
                 mUpperText = upperText;
                 return this;
             }
@@ -328,7 +327,7 @@
              * Sets the lower text.
              */
             @NonNull
-            public Builder setLowerText(@Nullable CharSequence lowerText) {
+            public Builder setLowerText(@Nullable SmartspaceText lowerText) {
                 mLowerText = lowerText;
                 return this;
             }
@@ -349,7 +348,8 @@
              */
             @NonNull
             public CarouselItem build() {
-                if (TextUtils.isEmpty(mUpperText) && mImage == null && TextUtils.isEmpty(
+                if (SmartspaceUtils.isEmpty(mUpperText) && mImage == null
+                        && SmartspaceUtils.isEmpty(
                         mLowerText)) {
                     throw new IllegalStateException("Carousel data is empty");
                 }
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java
index 7e2f74e..9d4c8e2 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java
@@ -47,15 +47,15 @@
     }
 
     private SmartspaceCombinedCardsUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable CharSequence titleText,
+            @Nullable SmartspaceText titleText,
             @Nullable SmartspaceIcon titleIcon,
-            @Nullable CharSequence subtitleText,
+            @Nullable SmartspaceText subtitleText,
             @Nullable SmartspaceIcon subTitleIcon,
             @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable CharSequence supplementalSubtitleText,
+            @Nullable SmartspaceText supplementalSubtitleText,
             @Nullable SmartspaceIcon supplementalSubtitleIcon,
             @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable CharSequence supplementalAlarmText,
+            @Nullable SmartspaceText supplementalAlarmText,
             @NonNull List<SmartspaceDefaultUiTemplateData> combinedCardDataList) {
         super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
                 supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
@@ -146,7 +146,7 @@
                 throw new IllegalStateException("Please assign a value to all @NonNull args.");
             }
             return new SmartspaceCombinedCardsUiTemplateData(getTemplateType(), getTitleText(),
-                    getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(),
+                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
                     getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
                     getSupplementalSubtitleTapAction(), getSupplementalAlarmText(),
                     mCombinedCardDataList);
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java
index 742d5c9..a7ac9c7 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java
@@ -24,7 +24,6 @@
 import android.app.smartspace.SmartspaceUtils;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
 
 import java.util.Objects;
 
@@ -50,17 +49,17 @@
      * will be used, which has its own tap action applied to the title area.
      */
     @Nullable
-    private final CharSequence mTitleText;
+    private final SmartspaceText mTitleText;
 
     @Nullable
     private final SmartspaceIcon mTitleIcon;
 
     /** Subtitle text and icon are shown at the second row. */
     @Nullable
-    private final CharSequence mSubtitleText;
+    private final SmartspaceText mSubtitleText;
 
     @Nullable
-    private final SmartspaceIcon mSubTitleIcon;
+    private final SmartspaceIcon mSubtitleIcon;
 
     /**
      * Primary tap action for the entire card, including the blank spaces, except: 1. When title is
@@ -75,7 +74,7 @@
      * Mainly used for weather info on non-weather card.
      */
     @Nullable
-    private final CharSequence mSupplementalSubtitleText;
+    private final SmartspaceText mSupplementalSubtitleText;
 
     @Nullable
     private final SmartspaceIcon mSupplementalSubtitleIcon;
@@ -92,19 +91,19 @@
      * alarm".
      */
     @Nullable
-    private final CharSequence mSupplementalAlarmText;
+    private final SmartspaceText mSupplementalAlarmText;
 
     SmartspaceDefaultUiTemplateData(@NonNull Parcel in) {
         mTemplateType = in.readInt();
-        mTitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mTitleText = in.readTypedObject(SmartspaceText.CREATOR);
         mTitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mSubtitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mSubTitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
+        mSubtitleText = in.readTypedObject(SmartspaceText.CREATOR);
+        mSubtitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
         mPrimaryTapAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
-        mSupplementalSubtitleText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mSupplementalSubtitleText = in.readTypedObject(SmartspaceText.CREATOR);
         mSupplementalSubtitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
         mSupplementalSubtitleTapAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
-        mSupplementalAlarmText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mSupplementalAlarmText = in.readTypedObject(SmartspaceText.CREATOR);
     }
 
     /**
@@ -112,20 +111,20 @@
      * SmartspaceDefaultUiTemplateData.Builder.
      */
     SmartspaceDefaultUiTemplateData(@UiTemplateType int templateType,
-            @Nullable CharSequence titleText,
+            @Nullable SmartspaceText titleText,
             @Nullable SmartspaceIcon titleIcon,
-            @Nullable CharSequence subtitleText,
-            @Nullable SmartspaceIcon subTitleIcon,
+            @Nullable SmartspaceText subtitleText,
+            @Nullable SmartspaceIcon subtitleIcon,
             @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable CharSequence supplementalSubtitleText,
+            @Nullable SmartspaceText supplementalSubtitleText,
             @Nullable SmartspaceIcon supplementalSubtitleIcon,
             @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable CharSequence supplementalAlarmText) {
+            @Nullable SmartspaceText supplementalAlarmText) {
         mTemplateType = templateType;
         mTitleText = titleText;
         mTitleIcon = titleIcon;
         mSubtitleText = subtitleText;
-        mSubTitleIcon = subTitleIcon;
+        mSubtitleIcon = subtitleIcon;
         mPrimaryTapAction = primaryTapAction;
         mSupplementalSubtitleText = supplementalSubtitleText;
         mSupplementalSubtitleIcon = supplementalSubtitleIcon;
@@ -139,7 +138,7 @@
     }
 
     @Nullable
-    public CharSequence getTitleText() {
+    public SmartspaceText getTitleText() {
         return mTitleText;
     }
 
@@ -149,17 +148,22 @@
     }
 
     @Nullable
-    public CharSequence getSubtitleText() {
+    public SmartspaceText getSubtitleText() {
         return mSubtitleText;
     }
 
     @Nullable
-    public SmartspaceIcon getSubTitleIcon() {
-        return mSubTitleIcon;
+    public SmartspaceIcon getSubtitleIcon() {
+        return mSubtitleIcon;
     }
 
     @Nullable
-    public CharSequence getSupplementalSubtitleText() {
+    public SmartspaceTapAction getPrimaryTapAction() {
+        return mPrimaryTapAction;
+    }
+
+    @Nullable
+    public SmartspaceText getSupplementalSubtitleText() {
         return mSupplementalSubtitleText;
     }
 
@@ -169,17 +173,12 @@
     }
 
     @Nullable
-    public SmartspaceTapAction getPrimaryTapAction() {
-        return mPrimaryTapAction;
-    }
-
-    @Nullable
     public SmartspaceTapAction getSupplementalSubtitleTapAction() {
         return mSupplementalSubtitleTapAction;
     }
 
     @Nullable
-    public CharSequence getSupplementalAlarmText() {
+    public SmartspaceText getSupplementalAlarmText() {
         return mSupplementalAlarmText;
     }
 
@@ -208,15 +207,15 @@
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeInt(mTemplateType);
-        TextUtils.writeToParcel(mTitleText, out, flags);
+        out.writeTypedObject(mTitleText, flags);
         out.writeTypedObject(mTitleIcon, flags);
-        TextUtils.writeToParcel(mSubtitleText, out, flags);
-        out.writeTypedObject(mSubTitleIcon, flags);
+        out.writeTypedObject(mSubtitleText, flags);
+        out.writeTypedObject(mSubtitleIcon, flags);
         out.writeTypedObject(mPrimaryTapAction, flags);
-        TextUtils.writeToParcel(mSupplementalSubtitleText, out, flags);
+        out.writeTypedObject(mSupplementalSubtitleText, flags);
         out.writeTypedObject(mSupplementalSubtitleIcon, flags);
         out.writeTypedObject(mSupplementalSubtitleTapAction, flags);
-        TextUtils.writeToParcel(mSupplementalAlarmText, out, flags);
+        out.writeTypedObject(mSupplementalAlarmText, flags);
     }
 
     @Override
@@ -228,7 +227,7 @@
                 that.mTitleText)
                 && Objects.equals(mTitleIcon, that.mTitleIcon)
                 && SmartspaceUtils.isEqual(mSubtitleText, that.mSubtitleText)
-                && Objects.equals(mSubTitleIcon, that.mSubTitleIcon)
+                && Objects.equals(mSubtitleIcon, that.mSubtitleIcon)
                 && Objects.equals(mPrimaryTapAction, that.mPrimaryTapAction)
                 && SmartspaceUtils.isEqual(mSupplementalSubtitleText,
                 that.mSupplementalSubtitleText)
@@ -240,7 +239,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mTemplateType, mTitleText, mTitleIcon, mSubtitleText, mSubTitleIcon,
+        return Objects.hash(mTemplateType, mTitleText, mTitleIcon, mSubtitleText, mSubtitleIcon,
                 mPrimaryTapAction, mSupplementalSubtitleText, mSupplementalSubtitleIcon,
                 mSupplementalSubtitleTapAction, mSupplementalAlarmText);
     }
@@ -252,7 +251,7 @@
                 + ", mTitleText=" + mTitleText
                 + ", mTitleIcon=" + mTitleIcon
                 + ", mSubtitleText=" + mSubtitleText
-                + ", mSubTitleIcon=" + mSubTitleIcon
+                + ", mSubTitleIcon=" + mSubtitleIcon
                 + ", mPrimaryTapAction=" + mPrimaryTapAction
                 + ", mSupplementalSubtitleText=" + mSupplementalSubtitleText
                 + ", mSupplementalSubtitleIcon=" + mSupplementalSubtitleIcon
@@ -271,15 +270,15 @@
     public static class Builder {
         @UiTemplateType
         private final int mTemplateType;
-        private CharSequence mTitleText;
+        private SmartspaceText mTitleText;
         private SmartspaceIcon mTitleIcon;
-        private CharSequence mSubtitleText;
-        private SmartspaceIcon mSubTitleIcon;
+        private SmartspaceText mSubtitleText;
+        private SmartspaceIcon mSubtitleIcon;
         private SmartspaceTapAction mPrimaryTapAction;
-        private CharSequence mSupplementalSubtitleText;
+        private SmartspaceText mSupplementalSubtitleText;
         private SmartspaceIcon mSupplementalSubtitleIcon;
         private SmartspaceTapAction mSupplementalSubtitleTapAction;
-        private CharSequence mSupplementalAlarmText;
+        private SmartspaceText mSupplementalAlarmText;
 
         /**
          * A builder for {@link SmartspaceDefaultUiTemplateData}.
@@ -300,7 +299,7 @@
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        CharSequence getTitleText() {
+        SmartspaceText getTitleText() {
             return mTitleText;
         }
 
@@ -314,15 +313,15 @@
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        CharSequence getSubtitleText() {
+        SmartspaceText getSubtitleText() {
             return mSubtitleText;
         }
 
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceIcon getSubTitleIcon() {
-            return mSubTitleIcon;
+        SmartspaceIcon getSubtitleIcon() {
+            return mSubtitleIcon;
         }
 
         /** Should ONLY be used by the subclasses */
@@ -335,7 +334,7 @@
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        CharSequence getSupplementalSubtitleText() {
+        SmartspaceText getSupplementalSubtitleText() {
             return mSupplementalSubtitleText;
         }
 
@@ -356,7 +355,7 @@
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        CharSequence getSupplementalAlarmText() {
+        SmartspaceText getSupplementalAlarmText() {
             return mSupplementalAlarmText;
         }
 
@@ -364,7 +363,7 @@
          * Sets the card title.
          */
         @NonNull
-        public Builder setTitleText(@NonNull CharSequence titleText) {
+        public Builder setTitleText(@NonNull SmartspaceText titleText) {
             mTitleText = titleText;
             return this;
         }
@@ -382,7 +381,7 @@
          * Sets the card subtitle.
          */
         @NonNull
-        public Builder setSubtitleText(@NonNull CharSequence subtitleText) {
+        public Builder setSubtitleText(@NonNull SmartspaceText subtitleText) {
             mSubtitleText = subtitleText;
             return this;
         }
@@ -391,8 +390,8 @@
          * Sets the card subtitle icon.
          */
         @NonNull
-        public Builder setSubTitleIcon(@NonNull SmartspaceIcon subTitleIcon) {
-            mSubTitleIcon = subTitleIcon;
+        public Builder setSubtitleIcon(@NonNull SmartspaceIcon subtitleIcon) {
+            mSubtitleIcon = subtitleIcon;
             return this;
         }
 
@@ -409,7 +408,8 @@
          * Sets the supplemental subtitle text.
          */
         @NonNull
-        public Builder setSupplementalSubtitleText(@NonNull CharSequence supplementalSubtitleText) {
+        public Builder setSupplementalSubtitleText(
+                @NonNull SmartspaceText supplementalSubtitleText) {
             mSupplementalSubtitleText = supplementalSubtitleText;
             return this;
         }
@@ -440,7 +440,7 @@
          * Sets the supplemental alarm text.
          */
         @NonNull
-        public Builder setSupplementalAlarmText(@NonNull CharSequence supplementalAlarmText) {
+        public Builder setSupplementalAlarmText(@NonNull SmartspaceText supplementalAlarmText) {
             mSupplementalAlarmText = supplementalAlarmText;
             return this;
         }
@@ -451,7 +451,7 @@
         @NonNull
         public SmartspaceDefaultUiTemplateData build() {
             return new SmartspaceDefaultUiTemplateData(mTemplateType, mTitleText, mTitleIcon,
-                    mSubtitleText, mSubTitleIcon, mPrimaryTapAction, mSupplementalSubtitleText,
+                    mSubtitleText, mSubtitleIcon, mPrimaryTapAction, mSupplementalSubtitleText,
                     mSupplementalSubtitleIcon, mSupplementalSubtitleTapAction,
                     mSupplementalAlarmText);
         }
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java
index c76af27..bcd12eb 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java
@@ -22,7 +22,6 @@
 import android.app.smartspace.SmartspaceTarget;
 import android.app.smartspace.SmartspaceUtils;
 import android.os.Parcel;
-import android.text.TextUtils;
 
 import java.util.Objects;
 
@@ -35,15 +34,15 @@
 public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultUiTemplateData {
 
     @Nullable
-    private final CharSequence mHeadToHeadTitle;
+    private final SmartspaceText mHeadToHeadTitle;
     @Nullable
     private final SmartspaceIcon mHeadToHeadFirstCompetitorIcon;
     @Nullable
     private final SmartspaceIcon mHeadToHeadSecondCompetitorIcon;
     @Nullable
-    private final CharSequence mHeadToHeadFirstCompetitorText;
+    private final SmartspaceText mHeadToHeadFirstCompetitorText;
     @Nullable
-    private final CharSequence mHeadToHeadSecondCompetitorText;
+    private final SmartspaceText mHeadToHeadSecondCompetitorText;
 
     /** Tap action for the head-to-head secondary card. */
     @Nullable
@@ -51,29 +50,29 @@
 
     SmartspaceHeadToHeadUiTemplateData(@NonNull Parcel in) {
         super(in);
-        mHeadToHeadTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mHeadToHeadTitle = in.readTypedObject(SmartspaceText.CREATOR);
         mHeadToHeadFirstCompetitorIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
         mHeadToHeadSecondCompetitorIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mHeadToHeadFirstCompetitorText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-        mHeadToHeadSecondCompetitorText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mHeadToHeadFirstCompetitorText = in.readTypedObject(SmartspaceText.CREATOR);
+        mHeadToHeadSecondCompetitorText = in.readTypedObject(SmartspaceText.CREATOR);
         mHeadToHeadAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
     }
 
     private SmartspaceHeadToHeadUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable CharSequence titleText,
+            @Nullable SmartspaceText titleText,
             @Nullable SmartspaceIcon titleIcon,
-            @Nullable CharSequence subtitleText,
+            @Nullable SmartspaceText subtitleText,
             @Nullable SmartspaceIcon subTitleIcon,
             @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable CharSequence supplementalSubtitleText,
+            @Nullable SmartspaceText supplementalSubtitleText,
             @Nullable SmartspaceIcon supplementalSubtitleIcon,
             @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable CharSequence supplementalAlarmText,
-            @Nullable CharSequence headToHeadTitle,
+            @Nullable SmartspaceText supplementalAlarmText,
+            @Nullable SmartspaceText headToHeadTitle,
             @Nullable SmartspaceIcon headToHeadFirstCompetitorIcon,
             @Nullable SmartspaceIcon headToHeadSecondCompetitorIcon,
-            @Nullable CharSequence headToHeadFirstCompetitorText,
-            @Nullable CharSequence headToHeadSecondCompetitorText,
+            @Nullable SmartspaceText headToHeadFirstCompetitorText,
+            @Nullable SmartspaceText headToHeadSecondCompetitorText,
             @Nullable SmartspaceTapAction headToHeadAction) {
         super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
                 supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
@@ -87,7 +86,7 @@
     }
 
     @Nullable
-    public CharSequence getHeadToHeadTitle() {
+    public SmartspaceText getHeadToHeadTitle() {
         return mHeadToHeadTitle;
     }
 
@@ -102,12 +101,12 @@
     }
 
     @Nullable
-    public CharSequence getHeadToHeadFirstCompetitorText() {
+    public SmartspaceText getHeadToHeadFirstCompetitorText() {
         return mHeadToHeadFirstCompetitorText;
     }
 
     @Nullable
-    public CharSequence getHeadToHeadSecondCompetitorText() {
+    public SmartspaceText getHeadToHeadSecondCompetitorText() {
         return mHeadToHeadSecondCompetitorText;
     }
 
@@ -141,11 +140,11 @@
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
         super.writeToParcel(out, flags);
-        TextUtils.writeToParcel(mHeadToHeadTitle, out, flags);
+        out.writeTypedObject(mHeadToHeadTitle, flags);
         out.writeTypedObject(mHeadToHeadFirstCompetitorIcon, flags);
         out.writeTypedObject(mHeadToHeadSecondCompetitorIcon, flags);
-        TextUtils.writeToParcel(mHeadToHeadFirstCompetitorText, out, flags);
-        TextUtils.writeToParcel(mHeadToHeadSecondCompetitorText, out, flags);
+        out.writeTypedObject(mHeadToHeadFirstCompetitorText, flags);
+        out.writeTypedObject(mHeadToHeadSecondCompetitorText, flags);
         out.writeTypedObject(mHeadToHeadAction, flags);
     }
 
@@ -195,11 +194,11 @@
     @SystemApi
     public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
 
-        private CharSequence mHeadToHeadTitle;
+        private SmartspaceText mHeadToHeadTitle;
         private SmartspaceIcon mHeadToHeadFirstCompetitorIcon;
         private SmartspaceIcon mHeadToHeadSecondCompetitorIcon;
-        private CharSequence mHeadToHeadFirstCompetitorText;
-        private CharSequence mHeadToHeadSecondCompetitorText;
+        private SmartspaceText mHeadToHeadFirstCompetitorText;
+        private SmartspaceText mHeadToHeadSecondCompetitorText;
         private SmartspaceTapAction mHeadToHeadAction;
 
         /**
@@ -213,7 +212,7 @@
          * Sets the head-to-head card's title
          */
         @NonNull
-        public Builder setHeadToHeadTitle(@Nullable CharSequence headToHeadTitle) {
+        public Builder setHeadToHeadTitle(@Nullable SmartspaceText headToHeadTitle) {
             mHeadToHeadTitle = headToHeadTitle;
             return this;
         }
@@ -243,7 +242,7 @@
          */
         @NonNull
         public Builder setHeadToHeadFirstCompetitorText(
-                @Nullable CharSequence headToHeadFirstCompetitorText) {
+                @Nullable SmartspaceText headToHeadFirstCompetitorText) {
             mHeadToHeadFirstCompetitorText = headToHeadFirstCompetitorText;
             return this;
         }
@@ -253,7 +252,7 @@
          */
         @NonNull
         public Builder setHeadToHeadSecondCompetitorText(
-                @Nullable CharSequence headToHeadSecondCompetitorText) {
+                @Nullable SmartspaceText headToHeadSecondCompetitorText) {
             mHeadToHeadSecondCompetitorText = headToHeadSecondCompetitorText;
             return this;
         }
@@ -273,7 +272,7 @@
         @NonNull
         public SmartspaceHeadToHeadUiTemplateData build() {
             return new SmartspaceHeadToHeadUiTemplateData(getTemplateType(), getTitleText(),
-                    getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(),
+                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
                     getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
                     getSupplementalSubtitleTapAction(), getSupplementalAlarmText(),
                     mHeadToHeadTitle,
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java
index 70b3095..1efbaeb 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java
@@ -42,14 +42,19 @@
     @Nullable
     private final CharSequence mContentDescription;
 
+    private final boolean mShouldTint;
+
     SmartspaceIcon(@NonNull Parcel in) {
         mIcon = in.readTypedObject(Icon.CREATOR);
         mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mShouldTint = in.readBoolean();
     }
 
-    private SmartspaceIcon(@NonNull Icon icon, @Nullable CharSequence contentDescription) {
+    private SmartspaceIcon(@NonNull Icon icon, @Nullable CharSequence contentDescription,
+            boolean shouldTint) {
         mIcon = icon;
         mContentDescription = contentDescription;
+        mShouldTint = shouldTint;
     }
 
     @NonNull
@@ -62,6 +67,11 @@
         return mContentDescription;
     }
 
+    /** Return shouldTint value. The default value is true. */
+    public boolean shouldTint() {
+        return mShouldTint;
+    }
+
     @NonNull
     public static final Creator<SmartspaceIcon> CREATOR = new Creator<SmartspaceIcon>() {
         @Override
@@ -80,13 +90,14 @@
         if (this == o) return true;
         if (!(o instanceof SmartspaceIcon)) return false;
         SmartspaceIcon that = (SmartspaceIcon) o;
-        return mIcon.equals(that.mIcon) && SmartspaceUtils.isEqual(mContentDescription,
-                that.mContentDescription);
+        return mIcon.toString().equals(that.mIcon.toString()) && SmartspaceUtils.isEqual(
+                mContentDescription,
+                that.mContentDescription) && mShouldTint == that.mShouldTint;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mIcon, mContentDescription);
+        return Objects.hash(mIcon.toString(), mContentDescription, mShouldTint);
     }
 
     @Override
@@ -98,13 +109,15 @@
     public void writeToParcel(@NonNull Parcel out, int flags) {
         out.writeTypedObject(mIcon, flags);
         TextUtils.writeToParcel(mContentDescription, out, flags);
+        out.writeBoolean(mShouldTint);
     }
 
     @Override
     public String toString() {
         return "SmartspaceIcon{"
-                + "mImage=" + mIcon
-                + ", mContentDescription='" + mContentDescription + '\''
+                + "mIcon=" + mIcon
+                + ", mContentDescription=" + mContentDescription
+                + ", mShouldTint=" + mShouldTint
                 + '}';
     }
 
@@ -118,14 +131,16 @@
 
         private Icon mIcon;
         private CharSequence mContentDescription;
+        private boolean mShouldTint;
 
         /**
-         * A builder for {@link SmartspaceIcon}.
+         * A builder for {@link SmartspaceIcon}, which sets shouldTint to true by default.
          *
-         * @param icon the icon image of this smartspace icon.
+         * @param icon the icon image of this {@link SmartspaceIcon} instance.
          */
         public Builder(@NonNull Icon icon) {
             mIcon = Objects.requireNonNull(icon);
+            mShouldTint = true;
         }
 
         /**
@@ -138,11 +153,20 @@
         }
 
         /**
+         * Sets should tint icon.
+         */
+        @NonNull
+        public Builder setShouldTint(boolean shouldTint) {
+            mShouldTint = shouldTint;
+            return this;
+        }
+
+        /**
          * Builds a new SmartspaceIcon instance.
          */
         @NonNull
         public SmartspaceIcon build() {
-            return new SmartspaceIcon(mIcon, mContentDescription);
+            return new SmartspaceIcon(mIcon, mContentDescription, mShouldTint);
         }
     }
 }
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java
index 287cf8e..2db13d31 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java
@@ -22,7 +22,6 @@
 import android.app.smartspace.SmartspaceTarget;
 import android.app.smartspace.SmartspaceUtils;
 import android.os.Parcel;
-import android.text.TextUtils;
 
 import java.util.Objects;
 
@@ -40,7 +39,7 @@
 
     /** Text for the sub-card, which shows below the icon when being set. */
     @Nullable
-    private final CharSequence mSubCardText;
+    private final SmartspaceText mSubCardText;
 
     /** Tap action for the sub-card secondary card. */
     @Nullable
@@ -49,22 +48,22 @@
     SmartspaceSubCardUiTemplateData(@NonNull Parcel in) {
         super(in);
         mSubCardIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mSubCardText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mSubCardText = in.readTypedObject(SmartspaceText.CREATOR);
         mSubCardAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
     }
 
     private SmartspaceSubCardUiTemplateData(int templateType,
-            @Nullable CharSequence titleText,
+            @Nullable SmartspaceText titleText,
             @Nullable SmartspaceIcon titleIcon,
-            @Nullable CharSequence subtitleText,
+            @Nullable SmartspaceText subtitleText,
             @Nullable SmartspaceIcon subTitleIcon,
             @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable CharSequence supplementalSubtitleText,
+            @Nullable SmartspaceText supplementalSubtitleText,
             @Nullable SmartspaceIcon supplementalSubtitleIcon,
             @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable CharSequence supplementalAlarmText,
+            @Nullable SmartspaceText supplementalAlarmText,
             @NonNull SmartspaceIcon subCardIcon,
-            @Nullable CharSequence subCardText,
+            @Nullable SmartspaceText subCardText,
             @Nullable SmartspaceTapAction subCardAction) {
         super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
                 supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
@@ -80,7 +79,7 @@
     }
 
     @Nullable
-    public CharSequence getSubCardText() {
+    public SmartspaceText getSubCardText() {
         return mSubCardText;
     }
 
@@ -115,7 +114,7 @@
     public void writeToParcel(@NonNull Parcel out, int flags) {
         super.writeToParcel(out, flags);
         out.writeTypedObject(mSubCardIcon, flags);
-        TextUtils.writeToParcel(mSubCardText, out, flags);
+        out.writeTypedObject(mSubCardText, flags);
         out.writeTypedObject(mSubCardAction, flags);
     }
 
@@ -153,7 +152,7 @@
     public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
 
         private final SmartspaceIcon mSubCardIcon;
-        private CharSequence mSubCardText;
+        private SmartspaceText mSubCardText;
         private SmartspaceTapAction mSubCardAction;
 
         /**
@@ -165,11 +164,11 @@
         }
 
         /**
-         * Sets the card title text.
+         * Sets the card text.
          */
         @NonNull
-        public Builder setSubCardAction(@NonNull CharSequence subCardTitleText) {
-            mSubCardText = subCardTitleText;
+        public Builder setSubCardText(@NonNull SmartspaceText subCardText) {
+            mSubCardText = subCardText;
             return this;
         }
 
@@ -188,7 +187,7 @@
         @NonNull
         public SmartspaceSubCardUiTemplateData build() {
             return new SmartspaceSubCardUiTemplateData(getTemplateType(), getTitleText(),
-                    getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(),
+                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
                     getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
                     getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubCardIcon,
                     mSubCardText,
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java
index c479993..2fe4cf8 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java
@@ -22,8 +22,6 @@
 import android.app.smartspace.SmartspaceTarget;
 import android.os.Parcel;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
@@ -37,7 +35,7 @@
 
     /** Texts are shown next to the image as a vertical list */
     @NonNull
-    private final List<CharSequence> mSubImageTexts;
+    private final List<SmartspaceText> mSubImageTexts;
 
     /** If multiple images are passed in, they will be rendered as GIF. */
     @NonNull
@@ -49,22 +47,22 @@
 
     SmartspaceSubImageUiTemplateData(@NonNull Parcel in) {
         super(in);
-        mSubImageTexts = Arrays.asList(in.readCharSequenceArray());
+        mSubImageTexts = in.createTypedArrayList(SmartspaceText.CREATOR);
         mSubImages = in.createTypedArrayList(SmartspaceIcon.CREATOR);
         mSubImageAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
     }
 
     private SmartspaceSubImageUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable CharSequence titleText,
+            @Nullable SmartspaceText titleText,
             @Nullable SmartspaceIcon titleIcon,
-            @Nullable CharSequence subtitleText,
+            @Nullable SmartspaceText subtitleText,
             @Nullable SmartspaceIcon subTitleIcon,
             @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable CharSequence supplementalSubtitleText,
+            @Nullable SmartspaceText supplementalSubtitleText,
             @Nullable SmartspaceIcon supplementalSubtitleIcon,
             @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable CharSequence supplementalAlarmText,
-            @NonNull List<CharSequence> subImageTexts,
+            @Nullable SmartspaceText supplementalAlarmText,
+            @NonNull List<SmartspaceText> subImageTexts,
             @NonNull List<SmartspaceIcon> subImages,
             @Nullable SmartspaceTapAction subImageAction) {
         super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
@@ -76,7 +74,7 @@
     }
 
     @NonNull
-    public List<CharSequence> getSubImageTexts() {
+    public List<SmartspaceText> getSubImageTexts() {
         return mSubImageTexts;
     }
 
@@ -115,7 +113,7 @@
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
         super.writeToParcel(out, flags);
-        out.writeCharSequenceList(new ArrayList<>(mSubImageTexts));
+        out.writeTypedList(mSubImageTexts);
         out.writeTypedList(mSubImages);
         out.writeTypedObject(mSubImageAction, flags);
     }
@@ -153,14 +151,14 @@
     @SystemApi
     public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
 
-        private final List<CharSequence> mSubImageTexts;
+        private final List<SmartspaceText> mSubImageTexts;
         private final List<SmartspaceIcon> mSubImages;
         private SmartspaceTapAction mSubImageAction;
 
         /**
          * A builder for {@link SmartspaceSubImageUiTemplateData}.
          */
-        public Builder(@NonNull List<CharSequence> subImageTexts,
+        public Builder(@NonNull List<SmartspaceText> subImageTexts,
                 @NonNull List<SmartspaceIcon> subImages) {
             super(SmartspaceTarget.UI_TEMPLATE_SUB_IMAGE);
             mSubImageTexts = Objects.requireNonNull(subImageTexts);
@@ -171,7 +169,7 @@
          * Sets the card tap action.
          */
         @NonNull
-        public Builder setCarouselAction(@NonNull SmartspaceTapAction subImageAction) {
+        public Builder setSubImageAction(@NonNull SmartspaceTapAction subImageAction) {
             mSubImageAction = subImageAction;
             return this;
         }
@@ -182,7 +180,7 @@
         @NonNull
         public SmartspaceSubImageUiTemplateData build() {
             return new SmartspaceSubImageUiTemplateData(getTemplateType(), getTitleText(),
-                    getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(),
+                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
                     getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
                     getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubImageTexts,
                     mSubImages,
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java
index b5d9645..9512c7f 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java
@@ -22,11 +22,10 @@
 import android.app.smartspace.SmartspaceTarget;
 import android.os.Parcel;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
+
 /**
  * Holds all the relevant data needed to render a Smartspace card with the sub-list Ui Template.
  *
@@ -38,7 +37,7 @@
     @Nullable
     private final SmartspaceIcon mSubListIcon;
     @NonNull
-    private final List<CharSequence> mSubListTexts;
+    private final List<SmartspaceText> mSubListTexts;
 
     /** Tap action for the sub-list secondary card. */
     @Nullable
@@ -47,22 +46,22 @@
     SmartspaceSubListUiTemplateData(@NonNull Parcel in) {
         super(in);
         mSubListIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mSubListTexts = Arrays.asList(in.readCharSequenceArray());
+        mSubListTexts = in.createTypedArrayList(SmartspaceText.CREATOR);
         mSubListAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
     }
 
     private SmartspaceSubListUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable CharSequence titleText,
+            @Nullable SmartspaceText titleText,
             @Nullable SmartspaceIcon titleIcon,
-            @Nullable CharSequence subtitleText,
+            @Nullable SmartspaceText subtitleText,
             @Nullable SmartspaceIcon subTitleIcon,
             @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable CharSequence supplementalSubtitleText,
+            @Nullable SmartspaceText supplementalSubtitleText,
             @Nullable SmartspaceIcon supplementalSubtitleIcon,
             @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable CharSequence supplementalAlarmText,
+            @Nullable SmartspaceText supplementalAlarmText,
             @Nullable SmartspaceIcon subListIcon,
-            @NonNull List<CharSequence> subListTexts,
+            @NonNull List<SmartspaceText> subListTexts,
             @Nullable SmartspaceTapAction subListAction) {
         super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
                 supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
@@ -78,7 +77,7 @@
     }
 
     @NonNull
-    public List<CharSequence> getSubListTexts() {
+    public List<SmartspaceText> getSubListTexts() {
         return mSubListTexts;
     }
 
@@ -113,7 +112,7 @@
     public void writeToParcel(@NonNull Parcel out, int flags) {
         super.writeToParcel(out, flags);
         out.writeTypedObject(mSubListIcon, flags);
-        out.writeCharSequenceList(new ArrayList<>(mSubListTexts));
+        out.writeTypedList(mSubListTexts);
         out.writeTypedObject(mSubListAction, flags);
     }
 
@@ -151,13 +150,13 @@
     public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
 
         private SmartspaceIcon mSubListIcon;
-        private final List<CharSequence> mSubListTexts;
+        private final List<SmartspaceText> mSubListTexts;
         private SmartspaceTapAction mSubListAction;
 
         /**
          * A builder for {@link SmartspaceSubListUiTemplateData}.
          */
-        public Builder(@NonNull List<CharSequence> subListTexts) {
+        public Builder(@NonNull List<SmartspaceText> subListTexts) {
             super(SmartspaceTarget.UI_TEMPLATE_SUB_LIST);
             mSubListTexts = Objects.requireNonNull(subListTexts);
         }
@@ -175,7 +174,7 @@
          * Sets the card tap action.
          */
         @NonNull
-        public Builder setCarouselAction(@NonNull SmartspaceTapAction subListAction) {
+        public Builder setSubListAction(@NonNull SmartspaceTapAction subListAction) {
             mSubListAction = subListAction;
             return this;
         }
@@ -186,7 +185,7 @@
         @NonNull
         public SmartspaceSubListUiTemplateData build() {
             return new SmartspaceSubListUiTemplateData(getTemplateType(), getTitleText(),
-                    getTitleIcon(), getSubtitleText(), getSubTitleIcon(), getPrimaryTapAction(),
+                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
                     getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
                     getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubListIcon,
                     mSubListTexts,
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceText.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceText.java
new file mode 100644
index 0000000..25d13e6
--- /dev/null
+++ b/core/java/android/app/smartspace/uitemplatedata/SmartspaceText.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 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.app.smartspace.uitemplatedata;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.smartspace.SmartspaceUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.Objects;
+
+/**
+ * Holds the information for a Smartspace-card text: the text content and
+ * the truncate_at information.
+ *
+ * @hide
+ */
+@SystemApi
+public final class SmartspaceText implements Parcelable {
+
+    @NonNull
+    private final CharSequence mText;
+
+    private final TextUtils.TruncateAt mTruncateAtType;
+
+    SmartspaceText(Parcel in) {
+        mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+        mTruncateAtType = TextUtils.TruncateAt.valueOf(in.readString());
+    }
+
+    private SmartspaceText(@NonNull CharSequence text, TextUtils.TruncateAt truncateAtType) {
+        mText = text;
+        mTruncateAtType = truncateAtType;
+    }
+
+    @NonNull
+    public CharSequence getText() {
+        return mText;
+    }
+
+    @NonNull
+    public TextUtils.TruncateAt getTruncateAtType() {
+        return mTruncateAtType;
+    }
+
+    @NonNull
+    public static final Creator<SmartspaceText> CREATOR = new Creator<SmartspaceText>() {
+        @Override
+        public SmartspaceText createFromParcel(Parcel in) {
+            return new SmartspaceText(in);
+        }
+
+        @Override
+        public SmartspaceText[] newArray(int size) {
+            return new SmartspaceText[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SmartspaceText)) return false;
+        SmartspaceText that = (SmartspaceText) o;
+        return mTruncateAtType == that.mTruncateAtType && SmartspaceUtils.isEqual(mText,
+                that.mText);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mText, mTruncateAtType);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        TextUtils.writeToParcel(mText, out, flags);
+        out.writeString(mTruncateAtType.name());
+    }
+
+    /**
+     * A builder for {@link SmartspaceText} object.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder {
+        private final CharSequence mText;
+        private TextUtils.TruncateAt mTruncateAtType;
+
+        /**
+         * A builder for {@link SmartspaceText}, which sets TruncateAtType to AT_END by default.
+         */
+        public Builder(@NonNull CharSequence text) {
+            mText = Objects.requireNonNull(text);
+            mTruncateAtType = TextUtils.TruncateAt.END;
+        }
+
+        /**
+         * A builder for {@link SmartspaceText}.
+         */
+        public Builder(@NonNull CharSequence text, @NonNull TextUtils.TruncateAt truncateAtType) {
+            mText = Objects.requireNonNull(text);
+            mTruncateAtType = Objects.requireNonNull(truncateAtType);
+        }
+
+        /**
+         * Sets truncateAtType.
+         */
+        @NonNull
+        public Builder setTruncateAtType(@NonNull TextUtils.TruncateAt truncateAtType) {
+            mTruncateAtType = Objects.requireNonNull(truncateAtType);
+            return this;
+        }
+
+        /**
+         * Builds a new SmartspaceText instance.
+         */
+        @NonNull
+        public SmartspaceText build() {
+            return new SmartspaceText(mText, mTruncateAtType);
+        }
+    }
+}
diff --git a/core/java/android/companion/TEST_MAPPING b/core/java/android/companion/TEST_MAPPING
index 63f54fa..b561c29 100644
--- a/core/java/android/companion/TEST_MAPPING
+++ b/core/java/android/companion/TEST_MAPPING
@@ -1,12 +1,7 @@
 {
-  "presubmit": [
+  "imports": [
     {
-      "name": "CtsOsTestCases",
-      "options": [
-        {
-          "include-filter": "android.os.cts.CompanionDeviceManagerTest"
-        }
-      ]
+      "path": "frameworks/base/services/companion"
     }
   ]
 }
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index 339e9a2..8fc24fd 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -77,4 +77,7 @@
     void launchPendingIntent(
             int displayId, in PendingIntent pendingIntent, in ResultReceiver resultReceiver);
     PointF getCursorPosition(IBinder token);
+
+    /** Sets whether to show or hide the cursor while this virtual device is active. */
+    void setShowPointerIcon(boolean showPointerIcon);
 }
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index bb9bb09..69033a6 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -338,6 +338,22 @@
         }
 
         /**
+         * Sets the visibility of the pointer icon for this VirtualDevice's associated displays.
+         *
+         * @param showPointerIcon True if the pointer should be shown; false otherwise. The default
+         *                        visibility is true.
+         */
+        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+        @NonNull
+        public void setShowPointerIcon(boolean showPointerIcon) {
+            try {
+                mVirtualDevice.setShowPointerIcon(showPointerIcon);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
          * Returns the display flags that should be added to a particular virtual display.
          * Additional device-level flags from {@link
          * com.android.server.companion.virtual.VirtualDeviceImpl#getBaseVirtualDisplayFlags()} will
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 157e709..3f2fa21 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -155,8 +155,8 @@
         this(AttributionSourceState.CREATOR.createFromParcel(in));
 
         // Since we just unpacked this object as part of it transiting a Binder
-        // call, this is the perfect time to enforce that its UID can be trusted
-        enforceCallingUid();
+        // call, this is the perfect time to enforce that its UID and PID can be trusted
+        enforceCallingUidAndPid();
     }
 
     /** @hide */
@@ -259,13 +259,24 @@
     }
 
     /**
+     * If you are handling an IPC and you don't trust the caller you need to validate whether the
+     * attribution source is one for the calling app to prevent the caller to pass you a source from
+     * another app without including themselves in the attribution chain.
+     *
+     * @throws SecurityException if the attribution source cannot be trusted to be from the caller.
+     */
+    private void enforceCallingUidAndPid() {
+        enforceCallingUid();
+        enforceCallingPid();
+    }
+
+    /**
      * If you are handling an IPC and you don't trust the caller you need to validate
      * whether the attribution source is one for the calling app to prevent the caller
      * to pass you a source from another app without including themselves in the
      * attribution chain.
      *
-     * @throws SecurityException if the attribution source cannot be trusted to be
-     * from the caller.
+     * @throws SecurityException if the attribution source cannot be trusted to be from the caller.
      */
     public void enforceCallingUid() {
         if (!checkCallingUid()) {
@@ -294,6 +305,33 @@
         return true;
     }
 
+    /**
+     * Validate that the pid being claimed for the calling app is not spoofed
+     *
+     * @throws SecurityException if the attribution source cannot be trusted to be from the caller.
+     * @hide
+     */
+    @TestApi
+    public void enforceCallingPid() {
+        if (!checkCallingPid()) {
+            throw new SecurityException("Calling pid: " + Binder.getCallingPid()
+                    + " doesn't match source pid: " + mAttributionSourceState.pid);
+        }
+    }
+
+    /**
+     * Validate that the pid being claimed for the calling app is not spoofed
+     *
+     * @return if the attribution source cannot be trusted to be from the caller.
+     */
+    private boolean checkCallingPid() {
+        final int callingPid = Binder.getCallingPid();
+        if (mAttributionSourceState.pid != -1 && callingPid != mAttributionSourceState.pid) {
+            return false;
+        }
+        return true;
+    }
+
     @Override
     public String toString() {
         if (Build.IS_DEBUGGABLE) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6ffea3f..2074125 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -6504,15 +6504,26 @@
      * <li>Each permission in {@code permissions} must be a runtime permission.
      * </ul>
      * <p>
-     * For every permission in {@code permissions}, the entire permission group it belongs to will
-     * be revoked. The revocation happens asynchronously and kills all processes running in the
-     * calling UID. It will be triggered once it is safe to do so. In particular, it will not be
-     * triggered as long as the package remains in the foreground, or has any active manifest
-     * components (e.g. when another app is accessing a content provider in the package).
+     * Background permissions which have no corresponding foreground permission still granted once
+     * the revocation is effective will also be revoked.
+     * <p>
+     * The revocation happens asynchronously and kills all processes running in the calling UID. It
+     * will be triggered once it is safe to do so. In particular, it will not be triggered as long
+     * as the package remains in the foreground, or has any active manifest components (e.g. when
+     * another app is accessing a content provider in the package).
      * <p>
      * If you want to revoke the permissions right away, you could call {@code System.exit()}, but
      * this could affect other apps that are accessing your app at the moment. For example, apps
      * accessing a content provider in your app will all crash.
+     * <p>
+     * Note that the settings UI shows a permission group as granted as long as at least one
+     * permission in the group is granted. If you want the user to observe the revocation in the
+     * settings, you should revoke every permission in the target group. To learn the current list
+     * of permissions in a group, you may use
+     * {@link PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)} and
+     * {@link PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)}. This list
+     * of permissions may evolve over time, so it is recommended to check whether it contains any
+     * permission you wish to retain before trying to revoke an entire group.
      *
      * @param permissions Collection of permissions to be revoked.
      * @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3e527f8..28bef56 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5576,6 +5576,7 @@
     /**
      * A String[] holding attribution tags when used with
      * {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+     * and ACTION_MANAGE_PERMISSION_USAGE
      *
      * E.g. an attribution tag could be location_provider, com.google.android.gms.*, etc.
      */
@@ -5584,17 +5585,20 @@
     /**
      * A long representing the start timestamp (epoch time in millis) of the permission usage
      * when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+     * and ACTION_MANAGE_PERMISSION_USAGE
      */
     public static final String EXTRA_START_TIME = "android.intent.extra.START_TIME";
 
     /**
      * A long representing the end timestamp (epoch time in millis) of the permission usage when
      * used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+     * and ACTION_MANAGE_PERMISSION_USAGE
      */
     public static final String EXTRA_END_TIME = "android.intent.extra.END_TIME";
 
     /**
-     * A boolean extra, when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD},
+     * A boolean extra, when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+     * and {@link #ACTION_MANAGE_PERMISSION_USAGE},
      * that specifies whether the permission usage system UI is showing attribution information
      * for the chosen entry.
      *
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9e9dd1e..567f649 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -19,6 +19,7 @@
 import static android.os.Build.VERSION_CODES.DONUT;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -48,6 +49,7 @@
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
@@ -62,58 +64,58 @@
     private static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
 
     /**
-     * Default task affinity of all activities in this application. See 
-     * {@link ActivityInfo#taskAffinity} for more information.  This comes 
-     * from the "taskAffinity" attribute. 
+     * Default task affinity of all activities in this application. See
+     * {@link ActivityInfo#taskAffinity} for more information.  This comes
+     * from the "taskAffinity" attribute.
      */
     public String taskAffinity;
-    
+
     /**
      * Optional name of a permission required to be able to access this
      * application's components.  From the "permission" attribute.
      */
     public String permission;
-    
+
     /**
      * The name of the process this application should run in.  From the
      * "process" attribute or, if not set, the same as
      * <var>packageName</var>.
      */
     public String processName;
-    
+
     /**
      * Class implementing the Application object.  From the "class"
      * attribute.
      */
     public String className;
-    
+
     /**
      * A style resource identifier (in the package's resources) of the
      * description of an application.  From the "description" attribute
      * or, if not set, 0.
      */
-    public int descriptionRes;    
-    
+    public int descriptionRes;
+
     /**
      * A style resource identifier (in the package's resources) of the
      * default visual theme of the application.  From the "theme" attribute
      * or, if not set, 0.
      */
     public int theme;
-    
+
     /**
      * Class implementing the Application's manage space
      * functionality.  From the "manageSpaceActivity"
      * attribute. This is an optional attribute and will be null if
      * applications don't specify it in their manifest
      */
-    public String manageSpaceActivityName;    
-    
+    public String manageSpaceActivityName;
+
     /**
      * Class implementing the Application's backup functionality.  From
      * the "backupAgent" attribute.  This is an optional attribute and
      * will be null if the application does not specify it in its manifest.
-     * 
+     *
      * <p>If android:allowBackup is set to false, this attribute is ignored.
      */
     public String backupAgentName;
@@ -174,7 +176,7 @@
      * {@code signatureOrSystem}.
      */
     public static final int FLAG_SYSTEM = 1<<0;
-    
+
     /**
      * Value for {@link #flags}: set to true if this application would like to
      * allow debugging of its
@@ -183,7 +185,7 @@
      * android:debuggable} of the &lt;application&gt; tag.
      */
     public static final int FLAG_DEBUGGABLE = 1<<1;
-    
+
     /**
      * Value for {@link #flags}: set to true if this application has code
      * associated with it.  Comes
@@ -191,7 +193,7 @@
      * android:hasCode} of the &lt;application&gt; tag.
      */
     public static final int FLAG_HAS_CODE = 1<<2;
-    
+
     /**
      * Value for {@link #flags}: set to true if this application is persistent.
      * Comes from {@link android.R.styleable#AndroidManifestApplication_persistent
@@ -212,20 +214,20 @@
      * android:allowTaskReparenting} of the &lt;application&gt; tag.
      */
     public static final int FLAG_ALLOW_TASK_REPARENTING = 1<<5;
-    
+
     /**
      * Value for {@link #flags}: default value for the corresponding ActivityInfo flag.
      * Comes from {@link android.R.styleable#AndroidManifestApplication_allowClearUserData
      * android:allowClearUserData} of the &lt;application&gt; tag.
      */
     public static final int FLAG_ALLOW_CLEAR_USER_DATA = 1<<6;
-    
+
     /**
      * Value for {@link #flags}: this is set if this application has been
      * installed as an update to a built-in system application.
      */
     public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7;
-    
+
     /**
      * Value for {@link #flags}: this is set if the application has specified
      * {@link android.R.styleable#AndroidManifestApplication_testOnly
@@ -240,15 +242,15 @@
      * android:smallScreens}.
      */
     public static final int FLAG_SUPPORTS_SMALL_SCREENS = 1<<9;
-    
+
     /**
      * Value for {@link #flags}: true when the application's window can be
      * displayed on normal screens.  Corresponds to
      * {@link android.R.styleable#AndroidManifestSupportsScreens_normalScreens
      * android:normalScreens}.
      */
-    public static final int FLAG_SUPPORTS_NORMAL_SCREENS = 1<<10; 
-    
+    public static final int FLAG_SUPPORTS_NORMAL_SCREENS = 1<<10;
+
     /**
      * Value for {@link #flags}: true when the application's window can be
      * increased in size for larger screens.  Corresponds to
@@ -256,7 +258,7 @@
      * android:largeScreens}.
      */
     public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<11;
-    
+
     /**
      * Value for {@link #flags}: true when the application knows how to adjust
      * its UI for different screen sizes.  Corresponds to
@@ -264,7 +266,7 @@
      * android:resizeable}.
      */
     public static final int FLAG_RESIZEABLE_FOR_SCREENS = 1<<12;
-    
+
     /**
      * Value for {@link #flags}: true when the application knows how to
      * accommodate different screen densities.  Corresponds to
@@ -276,7 +278,7 @@
      */
     @Deprecated
     public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 1<<13;
-    
+
     /**
      * Value for {@link #flags}: set to true if this application would like to
      * request the VM to operate under the safe mode. Comes from
@@ -288,7 +290,7 @@
     /**
      * Value for {@link #flags}: set to <code>false</code> if the application does not wish
      * to permit any OS-driven backups of its data; <code>true</code> otherwise.
-     * 
+     *
      * <p>Comes from the
      * {@link android.R.styleable#AndroidManifestApplication_allowBackup android:allowBackup}
      * attribute of the &lt;application&gt; tag.
@@ -351,7 +353,7 @@
      * android:xlargeScreens}.
      */
     public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19;
-    
+
     /**
      * Value for {@link #flags}: true when the application has requested a
      * large heap for its processes.  Corresponds to
@@ -1114,7 +1116,7 @@
      * the same uid).
      */
     public int uid;
-    
+
     /**
      * The minimum SDK version this application can run on. It will not run
      * on earlier versions.
@@ -1817,7 +1819,7 @@
             if (sb == null) {
                 sb = ab.packageName;
             }
-            
+
             return sCollator.compare(sa.toString(), sb.toString());
         }
 
@@ -1830,7 +1832,7 @@
     public ApplicationInfo() {
         createTimestamp = System.currentTimeMillis();
     }
-    
+
     public ApplicationInfo(ApplicationInfo orig) {
         super(orig);
         taskAffinity = orig.taskAffinity;
@@ -2125,7 +2127,7 @@
 
     /**
      * Disable compatibility mode
-     * 
+     *
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -2346,7 +2348,7 @@
         }
         return pm.getDefaultActivityIcon();
     }
-    
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private boolean isPackageUnavailable(PackageManager pm) {
         try {
@@ -2655,4 +2657,22 @@
     public int getLocaleConfigRes() {
         return localeConfigRes;
     }
+
+
+    /**
+     *  List of all shared libraries this application is linked against. This
+     *  list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+     *  PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving the structure.
+     *
+     * @hide
+     */
+    @NonNull
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public List<SharedLibraryInfo> getSharedLibraryInfos() {
+        if (sharedLibraryInfos == null) {
+            return Collections.EMPTY_LIST;
+        }
+        return sharedLibraryInfos;
+    }
+
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index aa64700..e9466e9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1063,6 +1063,7 @@
      * via this flag.
      * @hide
      */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int MATCH_STATIC_SHARED_AND_SDK_LIBRARIES = 0x04000000;
 
     /**
@@ -3325,7 +3326,8 @@
      * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined.
      */
     @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio";
+    public static final String FEATURE_TELEPHONY_RADIO_ACCESS =
+            "android.hardware.telephony.radio.access";
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java
index ed22de8..85890c1 100644
--- a/core/java/android/hardware/CameraStreamStats.java
+++ b/core/java/android/hardware/CameraStreamStats.java
@@ -16,6 +16,7 @@
 package android.hardware;
 
 import android.hardware.camera2.params.DynamicRangeProfiles;
+import android.hardware.camera2.CameraMetadata;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -47,6 +48,7 @@
     private float[] mHistogramBins;
     private long[] mHistogramCounts;
     private int mDynamicRangeProfile;
+    private int mStreamUseCase;
 
     private static final String TAG = "CameraStreamStats";
 
@@ -63,11 +65,13 @@
         mMaxAppBuffers = 0;
         mHistogramType = HISTOGRAM_TYPE_UNKNOWN;
         mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+        mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
     }
 
     public CameraStreamStats(int width, int height, int format,
             int dataSpace, long usage, long requestCount, long errorCount,
-            int startLatencyMs, int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile) {
+            int startLatencyMs, int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile,
+            int streamUseCase) {
         mWidth = width;
         mHeight = height;
         mFormat = format;
@@ -80,6 +84,7 @@
         mMaxAppBuffers = maxAppBuffers;
         mHistogramType = HISTOGRAM_TYPE_UNKNOWN;
         mDynamicRangeProfile = dynamicRangeProfile;
+        mStreamUseCase = streamUseCase;
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<CameraStreamStats> CREATOR =
@@ -126,6 +131,7 @@
         dest.writeFloatArray(mHistogramBins);
         dest.writeLongArray(mHistogramCounts);
         dest.writeInt(mDynamicRangeProfile);
+        dest.writeInt(mStreamUseCase);
     }
 
     public void readFromParcel(Parcel in) {
@@ -143,6 +149,7 @@
         mHistogramBins = in.createFloatArray();
         mHistogramCounts = in.createLongArray();
         mDynamicRangeProfile = in.readInt();
+        mStreamUseCase = in.readInt();
     }
 
     public int getWidth() {
@@ -200,4 +207,8 @@
     public int getDynamicRangeProfile() {
         return mDynamicRangeProfile;
     }
+
+    public int getStreamUseCase() {
+        return mStreamUseCase;
+    }
 }
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 95f13b5..3b6a564 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -1,3 +1,9 @@
+# Generic
+etalvala@google.com
+jreck@google.com
+michaelwr@google.com
+sumir@google.com
+
 # Camera
 per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,yinchiayeh@google.com,zhijunhe@google.com,jchowdhary@google.com
 
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 37cfb49..0d3aaf5 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -726,6 +726,89 @@
     public static final String STRING_TYPE_HEAD_TRACKER = "android.sensor.head_tracker";
 
     /**
+     * A constant describing a limited axes accelerometer sensor.
+     *
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     *
+     */
+    public static final int TYPE_ACCELEROMETER_LIMITED_AXES = 38;
+
+    /**
+     * A constant string describing a limited axes accelerometer sensor.
+     *
+     * @see #TYPE_ACCELEROMETER_LIMITED_AXES
+     *
+     */
+    public static final String STRING_TYPE_ACCELEROMETER_LIMITED_AXES =
+            "android.sensor.accelerometer_limited_axes";
+
+    /**
+     * A constant describing a limited axes gyroscope sensor.
+     *
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     *
+     */
+    public static final int TYPE_GYROSCOPE_LIMITED_AXES = 39;
+
+    /**
+     * A constant string describing a limited axes gyroscope sensor.
+     *
+     * @see #TYPE_GYROSCOPE_LIMITED_AXES
+     *
+     */
+    public static final String STRING_TYPE_GYROSCOPE_LIMITED_AXES =
+            "android.sensor.gyroscope_limited_axes";
+
+    /**
+     * A constant describing an uncalibrated limited axes accelerometer sensor.
+     *
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     *
+     */
+    public static final int TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40;
+
+    /**
+     * A constant string describing an uncalibrated limited axes accelerometer sensor.
+     *
+     * @see #TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED
+     *
+     */
+    public static final String STRING_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED =
+            "android.sensor.accelerometer_limited_axes_uncalibrated";
+
+    /**
+     * A constant describing an uncalibrated limited axes gyroscope sensor.
+     *
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     *
+     */
+    public static final int TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41;
+
+    /**
+     * A constant string describing an uncalibrated limited axes gyroscope sensor.
+     *
+     * @see #TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED
+     *
+     */
+    public static final String STRING_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED =
+            "android.sensor.gyroscope_limited_axes_uncalibrated";
+
+    /**
+     * A constant string describing a heading sensor.
+     *
+     * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+     */
+    public static final int TYPE_HEADING = 42;
+
+    /**
+     * A constant string describing a heading sensor.
+     *
+     * @see #TYPE_HEADING
+     *
+     */
+    public static final String STRING_TYPE_HEADING = "android.sensor.heading";
+
+    /**
      * A constant describing all sensor types.
      */
 
@@ -846,6 +929,11 @@
             6, // SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED
             1, // SENSOR_TYPE_HINGE_ANGLE
             6, // SENSOR_TYPE_HEAD_TRACKER (discontinuity count is excluded)
+            6, // SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES
+            6, // SENSOR_TYPE_GYROSCOPE_LIMITED_AXES
+            9, // SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED
+            9, // SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED
+            2, // SENSOR_TYPE_HEADING
     };
 
     /**
@@ -1301,6 +1389,21 @@
             case TYPE_HEAD_TRACKER:
                 mStringType = STRING_TYPE_HEAD_TRACKER;
                 return true;
+            case TYPE_ACCELEROMETER_LIMITED_AXES:
+                mStringType = STRING_TYPE_ACCELEROMETER_LIMITED_AXES;
+                return true;
+            case TYPE_GYROSCOPE_LIMITED_AXES:
+                mStringType = STRING_TYPE_GYROSCOPE_LIMITED_AXES;
+                return true;
+            case TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+                mStringType = STRING_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED;
+                return true;
+            case TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+                mStringType = STRING_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED;
+                return true;
+            case TYPE_HEADING:
+                mStringType = STRING_TYPE_HEADING;
+                return true;
             default:
                 return false;
         }
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index c77c8cc..45d4c09 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -676,6 +676,127 @@
      *  <li> values[5] : Z component of Euler vector representing angular velocity</li>
      * </ul>
      *
+     * <h4>{@link android.hardware.Sensor#TYPE_ACCELEROMETER_LIMITED_AXES
+     * Sensor.TYPE_ACCELEROMETER_LIMITED_AXES}:
+     * </h4> Equivalent to TYPE_ACCELEROMETER, but supporting cases where one
+     * or two axes are not supported.
+     *
+     * The last three values represent whether the acceleration value for a
+     * given axis is supported. A value of 1.0 indicates that the axis is
+     * supported, while a value of 0 means it isn't supported. The supported
+     * axes should be determined at build time and these values do not change
+     * during runtime.
+     *
+     * The acceleration values for axes that are not supported are set to 0.
+     *
+     * Similar to {@link android.hardware.Sensor#TYPE_ACCELEROMETER}.
+     *
+     * <ul>
+     * <li> values[0]: Acceleration minus Gx on the x-axis (if supported)</li>
+     * <li> values[1]: Acceleration minus Gy on the y-axis (if supported)</li>
+     * <li> values[2]: Acceleration minus Gz on the z-axis (if supported)</li>
+     * <li> values[3]: Acceleration supported for x-axis</li>
+     * <li> values[4]: Acceleration supported for y-axis</li>
+     * <li> values[5]: Acceleration supported for z-axis</li>
+     * </ul>
+     *
+     * <h4>{@link android.hardware.Sensor#TYPE_GYROSCOPE_LIMITED_AXES
+     * Sensor.TYPE_GYROSCOPE_LIMITED_AXES}:
+     * </h4> Equivalent to TYPE_GYROSCOPE, but supporting cases where one or two
+     * axes are not supported.
+     *
+     * The last three values represent whether the angular speed value for a
+     * given axis is supported. A value of 1.0 indicates that the axis is
+     * supported, while a value of 0 means it isn't supported. The supported
+     * axes should be determined at build time and these values do not change
+     * during runtime.
+     *
+     * The angular speed values for axes that are not supported are set to 0.
+     *
+     * Similar to {@link android.hardware.Sensor#TYPE_GYROSCOPE}.
+     *
+     * <ul>
+     * <li> values[0]: Angular speed around the x-axis (if supported)</li>
+     * <li> values[1]: Angular speed around the y-axis (if supported)</li>
+     * <li> values[2]: Angular speed around the z-axis (if supported)</li>
+     * <li> values[3]: Angular speed supported for x-axis</li>
+     * <li> values[4]: Angular speed supported for y-axis</li>
+     * <li> values[5]: Angular speed supported for z-axis</li>
+     * </ul>
+     * <p>
+     *
+     * <h4>{@link android.hardware.Sensor#TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED
+     * Sensor.TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED}:
+     * </h4> Equivalent to TYPE_ACCELEROMETER_UNCALIBRATED, but supporting cases
+     * where one or two axes are not supported.
+     *
+     * The last three values represent whether the acceleration value for a
+     * given axis is supported. A value of 1.0 indicates that the axis is
+     * supported, while a value of 0 means it isn't supported. The supported
+     * axes should be determined at build time and these values do not change
+     * during runtime.
+     *
+     * The acceleration values and bias values for axes that are not supported
+     * are set to 0.
+     *
+     * <ul>
+     * <li> values[0]: x_uncalib without bias compensation (if supported)</li>
+     * <li> values[1]: y_uncalib without bias compensation (if supported)</li>
+     * <li> values[2]: z_uncalib without bias compensation (if supported)</li>
+     * <li> values[3]: estimated x_bias (if supported)</li>
+     * <li> values[4]: estimated y_bias (if supported)</li>
+     * <li> values[5]: estimated z_bias (if supported)</li>
+     * <li> values[6]: Acceleration supported for x-axis</li>
+     * <li> values[7]: Acceleration supported for y-axis</li>
+     * <li> values[8]: Acceleration supported for z-axis</li>
+     * </ul>
+     * </p>
+     *
+     * <h4> {@link android.hardware.Sensor#TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED
+     * Sensor.TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED}:
+     * </h4> Equivalent to TYPE_GYROSCOPE_UNCALIBRATED, but supporting cases
+     * where one or two axes are not supported.
+     *
+     * The last three values represent whether the angular speed value for a
+     * given axis is supported. A value of 1.0 indicates that the axis is
+     * supported, while a value of 0 means it isn't supported. The supported
+     * axes should be determined at build time and these values do not change
+     * during runtime.
+     *
+     * The angular speed values and drift values for axes that are not supported
+     * are set to 0.
+     *
+     * <ul>
+     * <li> values[0]: Angular speed (w/o drift compensation) around the X axis (if supported)</li>
+     * <li> values[1]: Angular speed (w/o drift compensation) around the Y axis (if supported)</li>
+     * <li> values[2]: Angular speed (w/o drift compensation) around the Z axis (if supported)</li>
+     * <li> values[3]: estimated drift around X axis (if supported)</li>
+     * <li> values[4]: estimated drift around Y axis (if supported)</li>
+     * <li> values[5]: estimated drift around Z axis (if supported)</li>
+     * <li> values[6]: Angular speed supported for x-axis</li>
+     * <li> values[7]: Angular speed supported for y-axis</li>
+     * <li> values[8]: Angular speed supported for z-axis</li>
+     * </ul>
+     * </p>
+     *
+     * <h4>{@link android.hardware.Sensor#TYPE_HEADING Sensor.TYPE_HEADING}:</h4>
+     *
+     * A sensor of this type measures the direction in which the device is
+     * pointing relative to true north in degrees. The value must be between
+     * 0.0 (inclusive) and 360.0 (exclusive), with 0 indicating north, 90 east,
+     * 180 south, and 270 west.
+     *
+     * Accuracy is defined at 68% confidence. In the case where the underlying
+     * distribution is assumed Gaussian normal, this would be considered one
+     * standard deviation. For example, if heading returns 60 degrees, and
+     * accuracy returns 10 degrees, then there is a 68 percent probability of
+     * the true heading being between 50 degrees and 70 degrees.
+     *
+     * <ul>
+     *  <li> values[0]: Measured heading in degrees.</li>
+     *  <li> values[1]: Heading accuracy in degrees.</li>
+     * </ul>
+     *
      * @see GeomagneticField
      */
     public final float[] values;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index d2dc314..a06566c 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -657,7 +657,7 @@
      *
      * @throws IllegalArgumentException if metadataClass is not a subclass of CameraMetadata
      */
-    private <TKey> List<TKey>
+    <TKey> List<TKey>
     getAvailableKeyList(Class<?> metadataClass, Class<TKey> keyClass, int[] filterTags,
             boolean includeSynthetic) {
 
@@ -1678,6 +1678,9 @@
      * with PRIMARY_CAMERA.</p>
      * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, this position cannot be accurately
      * represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p>
+     * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is AUTOMOTIVE, then this position is relative to the
+     * origin of the automotive sensor coordinate system, which is at the center of the rear
+     * axle.</p>
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
@@ -1824,6 +1827,7 @@
      *   <li>{@link #LENS_POSE_REFERENCE_PRIMARY_CAMERA PRIMARY_CAMERA}</li>
      *   <li>{@link #LENS_POSE_REFERENCE_GYROSCOPE GYROSCOPE}</li>
      *   <li>{@link #LENS_POSE_REFERENCE_UNDEFINED UNDEFINED}</li>
+     *   <li>{@link #LENS_POSE_REFERENCE_AUTOMOTIVE AUTOMOTIVE}</li>
      * </ul>
      *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -1834,6 +1838,7 @@
      * @see #LENS_POSE_REFERENCE_PRIMARY_CAMERA
      * @see #LENS_POSE_REFERENCE_GYROSCOPE
      * @see #LENS_POSE_REFERENCE_UNDEFINED
+     * @see #LENS_POSE_REFERENCE_AUTOMOTIVE
      */
     @PublicKey
     @NonNull
@@ -2214,6 +2219,7 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR ULTRA_HIGH_RESOLUTION_SENSOR}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING REMOSAIC_REPROCESSING}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT DYNAMIC_RANGE_TEN_BIT}</li>
+     *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE STREAM_USE_CASE}</li>
      * </ul>
      *
      * <p>This key is available on all devices.</p>
@@ -2238,6 +2244,7 @@
      * @see #REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR
      * @see #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING
      * @see #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT
+     * @see #REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE
      */
     @PublicKey
     @NonNull
@@ -3475,6 +3482,90 @@
             new Key<Boolean>("android.scaler.multiResolutionStreamSupported", boolean.class);
 
     /**
+     * <p>The stream use cases supported by this camera device.</p>
+     * <p>The stream use case indicates the purpose of a particular camera stream from
+     * the end-user perspective. Some examples of camera use cases are: preview stream for
+     * live viewfinder shown to the user, still capture for generating high quality photo
+     * capture, video record for encoding the camera output for the purpose of future playback,
+     * and video call for live realtime video conferencing.</p>
+     * <p>With this flag, the camera device can optimize the image processing pipeline
+     * parameters, such as tuning, sensor mode, and ISP settings, indepedent of
+     * the properties of the immediate camera output surface. For example, if the output
+     * surface is a SurfaceTexture, the stream use case flag can be used to indicate whether
+     * the camera frames eventually go to display, video encoder,
+     * still image capture, or all of them combined.</p>
+     * <p>The application sets the use case of a camera stream by calling
+     * {@link android.hardware.camera2.params.OutputConfiguration#setStreamUseCase }.</p>
+     * <p>A camera device with
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
+     * capability must support the following stream use cases:</p>
+     * <ul>
+     * <li>DEFAULT</li>
+     * <li>PREVIEW</li>
+     * <li>STILL_CAPTURE</li>
+     * <li>VIDEO_RECORD</li>
+     * <li>PREVIEW_VIDEO_STILL</li>
+     * <li>VIDEO_CALL</li>
+     * </ul>
+     * <p>The guaranteed stream combinations related to stream use case for a camera device with
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
+     * capability is documented in the camera device
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline}. The
+     * application is strongly recommended to use one of the guaranteed stream combintations.
+     * If the application creates a session with a stream combination not in the guaranteed
+     * list, or with mixed DEFAULT and non-DEFAULT use cases within the same session,
+     * the camera device may ignore some stream use cases due to hardware constraints
+     * and implementation details.</p>
+     * <p>For stream combinations not covered by the stream use case mandatory lists, such as
+     * reprocessable session, constrained high speed session, or RAW stream combinations, the
+     * application should leave stream use cases within the session as DEFAULT.</p>
+     * <p><b>Possible values:</b></p>
+     * <ul>
+     *   <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT DEFAULT}</li>
+     *   <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW PREVIEW}</li>
+     *   <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE STILL_CAPTURE}</li>
+     *   <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD VIDEO_RECORD}</li>
+     *   <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL PREVIEW_VIDEO_STILL}</li>
+     *   <li>{@link #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL VIDEO_CALL}</li>
+     * </ul>
+     *
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     * @see #SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT
+     * @see #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW
+     * @see #SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE
+     * @see #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD
+     * @see #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL
+     * @see #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL
+     */
+    @PublicKey
+    @NonNull
+    public static final Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES =
+            new Key<int[]>("android.scaler.availableStreamUseCases", int[].class);
+
+    /**
+     * <p>An array of mandatory stream combinations with stream use cases.
+     * This is an app-readable conversion of the mandatory stream combination
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables} with
+     * each stream's use case being set.</p>
+     * <p>The array of
+     * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
+     * generated according to the documented
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for a
+     * camera device with
+     * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
+     * capability.
+     * The mandatory stream combination array will be {@code null} in case the device doesn't
+     * have {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
+     * capability.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    @NonNull
+    @SyntheticKey
+    public static final Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS =
+            new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryUseCaseStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
+
+    /**
      * <p>The area of the image sensor which corresponds to active pixels after any geometric
      * distortion correction has been applied.</p>
      * <p>This is the rectangle representing the size of the active region of the sensor (i.e.
@@ -5080,6 +5171,135 @@
     public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION =
             new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.heic.availableHeicStallDurationsMaximumResolution", android.hardware.camera2.params.StreamConfigurationDuration[].class);
 
+    /**
+     * <p>The direction of the camera faces relative to the vehicle body frame and the
+     * passenger seats.</p>
+     * <p>This enum defines the lens facing characteristic of the cameras on the automotive
+     * devices with locations {@link CameraCharacteristics#AUTOMOTIVE_LOCATION android.automotive.location} defines.  If the system has
+     * FEATURE_AUTOMOTIVE, the camera will have this entry in its static metadata.</p>
+     * <p>When {@link CameraCharacteristics#AUTOMOTIVE_LOCATION android.automotive.location} is INTERIOR, this has one or more INTERIOR_*
+     * values or a single EXTERIOR_* value.  When this has more than one INTERIOR_*,
+     * the first value must be the one for the seat closest to the optical axis. If this
+     * contains INTERIOR_OTHER, all other values will be ineffective.</p>
+     * <p>When {@link CameraCharacteristics#AUTOMOTIVE_LOCATION android.automotive.location} is EXTERIOR_* or EXTRA, this has a single
+     * EXTERIOR_* value.</p>
+     * <p>If a camera has INTERIOR_OTHER or EXTERIOR_OTHER, or more than one camera is at the
+     * same location and facing the same direction, their static metadata will list the
+     * following entries, so that applications can determain their lenses' exact facing
+     * directions:</p>
+     * <ul>
+     * <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
+     * </ul>
+     * <p><b>Possible values:</b></p>
+     * <ul>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER EXTERIOR_OTHER}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_EXTERIOR_FRONT EXTERIOR_FRONT}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_EXTERIOR_REAR EXTERIOR_REAR}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_EXTERIOR_LEFT EXTERIOR_LEFT}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_EXTERIOR_RIGHT EXTERIOR_RIGHT}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER INTERIOR_OTHER}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_LEFT INTERIOR_SEAT_ROW_1_LEFT}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_CENTER INTERIOR_SEAT_ROW_1_CENTER}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_RIGHT INTERIOR_SEAT_ROW_1_RIGHT}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_LEFT INTERIOR_SEAT_ROW_2_LEFT}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_CENTER INTERIOR_SEAT_ROW_2_CENTER}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_RIGHT INTERIOR_SEAT_ROW_2_RIGHT}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_LEFT INTERIOR_SEAT_ROW_3_LEFT}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_CENTER INTERIOR_SEAT_ROW_3_CENTER}</li>
+     *   <li>{@link #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_RIGHT INTERIOR_SEAT_ROW_3_RIGHT}</li>
+     * </ul>
+     *
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     * @see CameraCharacteristics#LENS_POSE_REFERENCE
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see #AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER
+     * @see #AUTOMOTIVE_LENS_FACING_EXTERIOR_FRONT
+     * @see #AUTOMOTIVE_LENS_FACING_EXTERIOR_REAR
+     * @see #AUTOMOTIVE_LENS_FACING_EXTERIOR_LEFT
+     * @see #AUTOMOTIVE_LENS_FACING_EXTERIOR_RIGHT
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_LEFT
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_CENTER
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_RIGHT
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_LEFT
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_CENTER
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_RIGHT
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_LEFT
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_CENTER
+     * @see #AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_RIGHT
+     */
+    @PublicKey
+    @NonNull
+    public static final Key<int[]> AUTOMOTIVE_LENS_FACING =
+            new Key<int[]>("android.automotive.lens.facing", int[].class);
+
+    /**
+     * <p>Location of the cameras on the automotive devices.</p>
+     * <p>This enum defines the locations of the cameras relative to the vehicle body frame on
+     * <a href="https://source.android.com/devices/sensors/sensor-types#auto_axes">the automotive sensor coordinate system</a>.
+     * If the system has FEATURE_AUTOMOTIVE, the camera will have this entry in its static
+     * metadata.</p>
+     * <ul>
+     * <li>INTERIOR is the inside of the vehicle body frame (or the passenger cabin).</li>
+     * <li>EXTERIOR is the outside of the vehicle body frame.</li>
+     * <li>EXTRA is the extra vehicle such as a trailer.</li>
+     * </ul>
+     * <p>Each side of the vehicle body frame on this coordinate system is defined as below:</p>
+     * <ul>
+     * <li>FRONT is where the Y-axis increases toward.</li>
+     * <li>REAR is where the Y-axis decreases toward.</li>
+     * <li>LEFT is where the X-axis decreases toward.</li>
+     * <li>RIGHT is where the X-axis increases toward.</li>
+     * </ul>
+     * <p>If the camera has either EXTERIOR_OTHER or EXTRA_OTHER, its static metadata will list
+     * the following entries, so that applications can determine the camera's exact location:</p>
+     * <ul>
+     * <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
+     * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
+     * </ul>
+     * <p><b>Possible values:</b></p>
+     * <ul>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_INTERIOR INTERIOR}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTERIOR_OTHER EXTERIOR_OTHER}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTERIOR_FRONT EXTERIOR_FRONT}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTERIOR_REAR EXTERIOR_REAR}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTERIOR_LEFT EXTERIOR_LEFT}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT EXTERIOR_RIGHT}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTRA_OTHER EXTRA_OTHER}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTRA_FRONT EXTRA_FRONT}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTRA_REAR EXTRA_REAR}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTRA_LEFT EXTRA_LEFT}</li>
+     *   <li>{@link #AUTOMOTIVE_LOCATION_EXTRA_RIGHT EXTRA_RIGHT}</li>
+     * </ul>
+     *
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_REFERENCE
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see #AUTOMOTIVE_LOCATION_INTERIOR
+     * @see #AUTOMOTIVE_LOCATION_EXTERIOR_OTHER
+     * @see #AUTOMOTIVE_LOCATION_EXTERIOR_FRONT
+     * @see #AUTOMOTIVE_LOCATION_EXTERIOR_REAR
+     * @see #AUTOMOTIVE_LOCATION_EXTERIOR_LEFT
+     * @see #AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT
+     * @see #AUTOMOTIVE_LOCATION_EXTRA_OTHER
+     * @see #AUTOMOTIVE_LOCATION_EXTRA_FRONT
+     * @see #AUTOMOTIVE_LOCATION_EXTRA_REAR
+     * @see #AUTOMOTIVE_LOCATION_EXTRA_LEFT
+     * @see #AUTOMOTIVE_LOCATION_EXTRA_RIGHT
+     */
+    @PublicKey
+    @NonNull
+    public static final Key<Integer> AUTOMOTIVE_LOCATION =
+            new Key<Integer>("android.automotive.location", int.class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 47eb79d..1a42eaf 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -404,7 +404,10 @@
      *                                  (output format)/(surface type), or if the extension is not
      *                                  supported, or if any of the output configurations select
      *                                  a dynamic range different from
-     *                                  {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD}
+     *                                  {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD},
+     *                                  or if any of the output configurations sets a stream use
+     *                                  case different from {@link
+     *                                  android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT}.
      * @see CameraExtensionCharacteristics#getSupportedExtensions
      * @see CameraExtensionCharacteristics#getExtensionSupportedSizes
      */
@@ -855,6 +858,31 @@
      * will cause a capture session initialization failure.
      * </p>
      *
+     * <p>Devices with the STREAM_USE_CASE capability ({@link
+     * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes {@link
+     * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}) support below additional
+     * stream combinations:
+     *
+     * <table>
+     * <tr><th colspan="10">STREAM_USE_CASE capability additional guaranteed configurations</th></tr>
+     * <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
+     * <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr>
+     * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Simple preview or in-app image processing</td> </tr>
+     * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code VIDEO_RECORD}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Simple video recording or in-app video processing</td> </tr>
+     * <tr> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Simple JPEG or YUV still image capture</td> </tr>
+     * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code PREVIEW_VIDEO_STILL}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Multi-purpose stream for preview, video and still image capture</td> </tr>
+     * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code VIDEO_CALL}</td> <td colspan="3" id="rb"></td> <td colspan="3" id="rb"></td> <td>Simple video call</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td>Preview with JPEG or YUV still image capture</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code VIDEO_RECORD}</td> <td colspan="3" id="rb"></td> <td>Preview with video recording or in-app video processing</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td colspan="3" id="rb"></td> <td>Preview with in-application image processing</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code VIDEO_CALL}</td> <td colspan="3" id="rb"></td> <td>Preview with video call</td> </tr>
+     * <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code PREVIEW_VIDEO_STILL}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td>Multi-purpose stream with JPEG or YUV still capture</td> </tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td>YUV and JPEG concurrent still image capture (for testing)</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code VIDEO_RECORD}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>Preview, video record and JPEG or YUV video snapshot</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>Preview, in-application image processing, and JPEG or YUV still image capture</td> </tr>
+     * </table><br>
+     * </p>
+     *
      * <p>Since the capabilities of camera devices vary greatly, a given camera device may support
      * target combinations with sizes outside of these guarantees, but this can only be tested for
      * by calling {@link #isSessionConfigurationSupported} or attempting to create a session with
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 5c636c7..aa98f1f 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -30,6 +30,7 @@
 import android.hardware.camera2.extension.IPreviewExtenderImpl;
 import android.hardware.camera2.extension.LatencyRange;
 import android.hardware.camera2.extension.SizeList;
+import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.params.ExtensionSessionConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.os.ConditionVariable;
@@ -49,6 +50,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -785,8 +787,8 @@
                 if (latencyRange != null) {
                     return new Range(latencyRange.min, latencyRange.max);
                 }
-        }
-    } catch (RemoteException e) {
+            }
+        } catch (RemoteException e) {
             Log.e(TAG, "Failed to query the extension capture latency! Extension service does"
                     + " not respond!");
         } finally {
@@ -795,4 +797,142 @@
 
         return null;
     }
+
+    /**
+     * Returns the set of keys supported by a {@link CaptureRequest} submitted in a
+     * {@link CameraExtensionSession} with a given extension type.
+     *
+     * <p>The set returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * @param extension the extension type
+     *
+     * @return non-modifiable set of capture keys supported by camera extension session initialized
+     *         with the given extension type.
+     * @throws IllegalArgumentException in case of unsupported extension.
+     */
+    @NonNull
+    public Set<CaptureRequest.Key> getAvailableCaptureRequestKeys(@Extension int extension) {
+        long clientId = registerClient(mContext);
+        if (clientId < 0) {
+            throw new IllegalArgumentException("Unsupported extensions");
+        }
+
+        HashSet<CaptureRequest.Key> ret = new HashSet<>();
+
+        try {
+            if (!isExtensionSupported(mCameraId, extension, mChars)) {
+                throw new IllegalArgumentException("Unsupported extension");
+            }
+            Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
+                    initializeExtension(extension);
+            extenders.second.onInit(mCameraId, mChars.getNativeMetadata());
+            extenders.second.init(mCameraId, mChars.getNativeMetadata());
+            CameraMetadataNative captureRequestMeta =
+                    extenders.second.getAvailableCaptureRequestKeys();
+
+            if (captureRequestMeta != null) {
+                int[] requestKeys = captureRequestMeta.get(
+                        CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS);
+                if (requestKeys == null) {
+                    throw new AssertionError("android.request.availableRequestKeys must be non-null"
+                            + " in the characteristics");
+                }
+                CameraCharacteristics requestChars = new CameraCharacteristics(captureRequestMeta);
+
+                Object crKey = CaptureRequest.Key.class;
+                Class<CaptureRequest.Key<?>> crKeyTyped = (Class<CaptureRequest.Key<?>>)crKey;
+
+                ret.addAll(requestChars.getAvailableKeyList(CaptureRequest.class, crKeyTyped,
+                        requestKeys, /*includeSynthetic*/ false));
+            }
+
+            // Jpeg quality and orientation must always be supported
+            if (!ret.contains(CaptureRequest.JPEG_QUALITY)) {
+                ret.add(CaptureRequest.JPEG_QUALITY);
+            }
+            if (!ret.contains(CaptureRequest.JPEG_ORIENTATION)) {
+                ret.add(CaptureRequest.JPEG_ORIENTATION);
+            }
+            extenders.second.onDeInit();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to query the available capture request keys!");
+        } finally {
+            unregisterClient(clientId);
+        }
+
+        return Collections.unmodifiableSet(ret);
+    }
+
+    /**
+     * Returns the set of keys supported by a {@link CaptureResult} passed as an argument to
+     * {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureResultAvailable}.
+     *
+     * <p>The set returned is not modifiable, so any attempts to modify it will throw
+     * a {@code UnsupportedOperationException}.</p>
+     *
+     * <p>In case the set is empty, then the extension is not able to support any capture results
+     * and the {@link CameraExtensionSession.ExtensionCaptureCallback#onCaptureResultAvailable}
+     * callback will not be fired.</p>
+     *
+     * @param extension the extension type
+     *
+     * @return non-modifiable set of capture result keys supported by camera extension session
+     *         initialized with the given extension type.
+     * @throws IllegalArgumentException in case of unsupported extension.
+     */
+    @NonNull
+    public Set<CaptureResult.Key> getAvailableCaptureResultKeys(@Extension int extension) {
+        long clientId = registerClient(mContext);
+        if (clientId < 0) {
+            throw new IllegalArgumentException("Unsupported extensions");
+        }
+
+        HashSet<CaptureResult.Key> ret = new HashSet<>();
+        try {
+            if (!isExtensionSupported(mCameraId, extension, mChars)) {
+                throw new IllegalArgumentException("Unsupported extension");
+            }
+
+            Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
+                    initializeExtension(extension);
+            extenders.second.onInit(mCameraId, mChars.getNativeMetadata());
+            extenders.second.init(mCameraId, mChars.getNativeMetadata());
+            CameraMetadataNative captureResultMeta =
+                    extenders.second.getAvailableCaptureResultKeys();
+
+            if (captureResultMeta != null) {
+                int[] resultKeys = captureResultMeta.get(
+                        CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS);
+                if (resultKeys == null) {
+                    throw new AssertionError("android.request.availableResultKeys must be non-null "
+                            + "in the characteristics");
+                }
+                CameraCharacteristics resultChars = new CameraCharacteristics(captureResultMeta);
+                Object crKey = CaptureResult.Key.class;
+                Class<CaptureResult.Key<?>> crKeyTyped = (Class<CaptureResult.Key<?>>)crKey;
+
+                ret.addAll(resultChars.getAvailableKeyList(CaptureResult.class, crKeyTyped,
+                        resultKeys, /*includeSynthetic*/ false));
+
+                // Jpeg quality, orientation and sensor timestamp must always be supported
+                if (!ret.contains(CaptureResult.JPEG_QUALITY)) {
+                    ret.add(CaptureResult.JPEG_QUALITY);
+                }
+                if (!ret.contains(CaptureResult.JPEG_ORIENTATION)) {
+                    ret.add(CaptureResult.JPEG_ORIENTATION);
+                }
+                if (!ret.contains(CaptureResult.SENSOR_TIMESTAMP)) {
+                    ret.add(CaptureResult.SENSOR_TIMESTAMP);
+                }
+            }
+            extenders.second.onDeInit();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to query the available capture result keys!");
+        } finally {
+            unregisterClient(clientId);
+        }
+
+        return Collections.unmodifiableSet(ret);
+    }
 }
diff --git a/core/java/android/hardware/camera2/CameraExtensionSession.java b/core/java/android/hardware/camera2/CameraExtensionSession.java
index 5892f68..ee3441f 100644
--- a/core/java/android/hardware/camera2/CameraExtensionSession.java
+++ b/core/java/android/hardware/camera2/CameraExtensionSession.java
@@ -172,6 +172,32 @@
                 int sequenceId) {
             // default empty implementation
         }
+
+        /**
+         * This method is called when an image capture has fully completed and all the
+         * result metadata is available.
+         *
+         * <p>This callback will only be called in case
+         * {@link CameraExtensionCharacteristics#getAvailableCaptureResultKeys} returns a valid
+         * non-empty list.</p>
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param session The session received during
+         *                {@link StateCallback#onConfigured(CameraExtensionSession)}
+         * @param request The request that was given to the CameraDevice
+         * @param result The total output metadata from the capture, which only includes the
+         * capture result keys advertised as supported in
+         * {@link CameraExtensionCharacteristics#getAvailableCaptureResultKeys}.
+         *
+         * @see #capture
+         * @see #setRepeatingRequest
+         * @see CameraExtensionCharacteristics#getAvailableCaptureResultKeys
+         */
+        public void onCaptureResultAvailable(@NonNull CameraExtensionSession session,
+                @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
+            // default empty implementation
+        }
     }
 
     /**
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 803684d..40565b0 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -407,6 +407,15 @@
      */
     public static final int LENS_POSE_REFERENCE_UNDEFINED = 2;
 
+    /**
+     * <p>The value of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} is relative to the origin of the
+     * automotive sensor coodinate system, which is at the center of the rear axle.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#LENS_POSE_REFERENCE
+     */
+    public static final int LENS_POSE_REFERENCE_AUTOMOTIVE = 3;
+
     //
     // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
     //
@@ -1210,6 +1219,36 @@
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT = 18;
 
+    /**
+     * <p>The camera device supports selecting a per-stream use case via
+     * {@link android.hardware.camera2.params.OutputConfiguration#setStreamUseCase }
+     * so that the device can optimize camera pipeline parameters such as tuning, sensor
+     * mode, or ISP settings for a specific user scenario.
+     * Some sample usages of this capability are:
+     * * Distinguish high quality YUV captures from a regular YUV stream where
+     *   the image quality may not be as good as the JPEG stream, or
+     * * Use one stream to serve multiple purposes: viewfinder, video recording and
+     *   still capture. This is common with applications that wish to apply edits equally
+     *   to preview, saved images, and saved videos.</p>
+     * <p>This capability requires the camera device to support the following
+     * stream use cases:
+     * * DEFAULT for backward compatibility where the application doesn't set
+     *   a stream use case
+     * * PREVIEW for live viewfinder and in-app image analysis
+     * * STILL_CAPTURE for still photo capture
+     * * VIDEO_RECORD for recording video clips
+     * * PREVIEW_VIDEO_STILL for one single stream used for viewfinder, video
+     *   recording, and still capture.
+     * * VIDEO_CALL for long running video calls</p>
+     * <p>{@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES }
+     * lists all of the supported stream use cases.</p>
+     * <p>Refer to {@link android.hardware.camera2.CameraDevice#createCaptureSession } for the
+     * mandatory stream combinations involving stream use cases, which can also be queried
+     * via {@link android.hardware.camera2.params.MandatoryStreamCombination }.</p>
+     * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+     */
+    public static final int REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19;
+
     //
     // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
     //
@@ -1336,6 +1375,89 @@
     public static final int SCALER_CROPPING_TYPE_FREEFORM = 1;
 
     //
+    // Enumeration values for CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+    //
+
+    /**
+     * <p>Default stream use case.</p>
+     * <p>This use case is the same as when the application doesn't set any use case for
+     * the stream. The camera device uses the properties of the output target, such as
+     * format, dataSpace, or surface class type, to optimize the image processing pipeline.</p>
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+     */
+    public static final int SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0x0;
+
+    /**
+     * <p>Live stream shown to the user.</p>
+     * <p>Optimized for performance and usability as a viewfinder, but not necessarily for
+     * image quality. The output is not meant to be persisted as saved images or video.</p>
+     * <p>No stall if android.control.<em> are set to FAST; may have stall if android.control.</em>
+     * are set to HIGH_QUALITY. This use case has the same behavior as the default
+     * SurfaceView and SurfaceTexture targets. Additionally, this use case can be used for
+     * in-app image analysis.</p>
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+     */
+    public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1;
+
+    /**
+     * <p>Still photo capture.</p>
+     * <p>Optimized for high-quality high-resolution capture, and not expected to maintain
+     * preview-like frame rates.</p>
+     * <p>The stream may have stalls regardless of whether android.control.* is HIGH_QUALITY.
+     * This use case has the same behavior as the default JPEG and RAW related formats.</p>
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+     */
+    public static final int SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 0x2;
+
+    /**
+     * <p>Recording video clips.</p>
+     * <p>Optimized for high-quality video capture, including high-quality image stabilization
+     * if supported by the device and enabled by the application. As a result, may produce
+     * output frames with a substantial lag from real time, to allow for highest-quality
+     * stabilization or other processing. As such, such an output is not suitable for drawing
+     * to screen directly, and is expected to be persisted to disk or similar for later
+     * playback or processing. Only streams that set the VIDEO_RECORD use case are guaranteed
+     * to have video stabilization applied when the video stabilization control is set
+     * to ON, as opposed to PREVIEW_STABILIZATION.</p>
+     * <p>This use case has the same behavior as the default MediaRecorder and MediaCodec
+     * targets.</p>
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+     */
+    public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3;
+
+    /**
+     * <p>One single stream used for combined purposes of preview, video, and still capture.</p>
+     * <p>For such multi-purpose streams, the camera device aims to make the best tradeoff
+     * between the individual use cases. For example, the STILL_CAPTURE use case by itself
+     * may have stalls for achieving best image quality. But if combined with PREVIEW and
+     * VIDEO_RECORD, the camera device needs to trade off the additional image processing
+     * for speed so that preview and video recording aren't slowed down.</p>
+     * <p>Similarly, VIDEO_RECORD may produce frames with a substantial lag, but
+     * PREVIEW_VIDEO_STILL must have minimal output delay. This means that to enable video
+     * stabilization with this use case, the device must support and the app must select the
+     * PREVIEW_STABILIZATION mode for video stabilization.</p>
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+     */
+    public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4;
+
+    /**
+     * <p>Long-running video call optimized for both power efficienty and video quality.</p>
+     * <p>The camera sensor may run in a lower-resolution mode to reduce power consumption
+     * at the cost of some image and digital zoom quality. Unlike VIDEO_RECORD, VIDEO_CALL
+     * outputs are expected to work in dark conditions, so are usually accompanied with
+     * variable frame rate settings to allow sufficient exposure time in low light.</p>
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+     */
+    public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5;
+
+    /**
+     * <p>Vendor defined use cases. These depend on the vendor implementation.</p>
+     * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+     * @hide
+     */
+    public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000;
+
+    //
     // Enumeration values for CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
     //
 
@@ -1716,6 +1838,191 @@
     public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED = 1;
 
     //
+    // Enumeration values for CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+    //
+
+    /**
+     * <p>The camera device faces the outside of the vehicle body frame but not exactly
+     * one of the exterior sides defined by this enum.  Applications should determine
+     * the exact facing direction from {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} and
+     * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER = 0;
+
+    /**
+     * <p>The camera device faces the front of the vehicle body frame.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_FRONT = 1;
+
+    /**
+     * <p>The camera device faces the rear of the vehicle body frame.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_REAR = 2;
+
+    /**
+     * <p>The camera device faces the left side of the vehicle body frame.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_LEFT = 3;
+
+    /**
+     * <p>The camera device faces the right side of the vehicle body frame.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_EXTERIOR_RIGHT = 4;
+
+    /**
+     * <p>The camera device faces the inside of the vehicle body frame but not exactly
+     * one of seats described by this enum.  Applications should determine the exact
+     * facing direction from {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} and {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER = 5;
+
+    /**
+     * <p>The camera device faces the left side seat of the first row.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_LEFT = 6;
+
+    /**
+     * <p>The camera device faces the center seat of the first row.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_CENTER = 7;
+
+    /**
+     * <p>The camera device faces the right seat of the first row.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_RIGHT = 8;
+
+    /**
+     * <p>The camera device faces the left side seat of the second row.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_LEFT = 9;
+
+    /**
+     * <p>The camera device faces the center seat of the second row.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_CENTER = 10;
+
+    /**
+     * <p>The camera device faces the right side seat of the second row.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_RIGHT = 11;
+
+    /**
+     * <p>The camera device faces the left side seat of the third row.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_LEFT = 12;
+
+    /**
+     * <p>The camera device faces the center seat of the third row.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_CENTER = 13;
+
+    /**
+     * <p>The camera device faces the right seat of the third row.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LENS_FACING
+     */
+    public static final int AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_RIGHT = 14;
+
+    //
+    // Enumeration values for CameraCharacteristics#AUTOMOTIVE_LOCATION
+    //
+
+    /**
+     * <p>The camera device exists inside of the vehicle cabin.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_INTERIOR = 0;
+
+    /**
+     * <p>The camera exists outside of the vehicle body frame but not exactly on one of the
+     * exterior locations this enum defines.  The applications should determine the exact
+     * location from {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTERIOR_OTHER = 1;
+
+    /**
+     * <p>The camera device exists outside of the vehicle body frame and on its front side.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTERIOR_FRONT = 2;
+
+    /**
+     * <p>The camera device exists outside of the vehicle body frame and on its rear side.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTERIOR_REAR = 3;
+
+    /**
+     * <p>The camera device exists outside and on left side of the vehicle body frame.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTERIOR_LEFT = 4;
+
+    /**
+     * <p>The camera device exists outside and on right side of the vehicle body frame.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT = 5;
+
+    /**
+     * <p>The camera device exists on an extra vehicle, such as the trailer, but not exactly
+     * on one of front, rear, left, or right side.  Applications should determine the exact
+     * location from {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTRA_OTHER = 6;
+
+    /**
+     * <p>The camera device exists outside of the extra vehicle's body frame and on its front
+     * side.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTRA_FRONT = 7;
+
+    /**
+     * <p>The camera device exists outside of the extra vehicle's body frame and on its rear
+     * side.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTRA_REAR = 8;
+
+    /**
+     * <p>The camera device exists outside and on left side of the extra vehicle body.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTRA_LEFT = 9;
+
+    /**
+     * <p>The camera device exists outside and on right side of the extra vehicle body.</p>
+     * @see CameraCharacteristics#AUTOMOTIVE_LOCATION
+     */
+    public static final int AUTOMOTIVE_LOCATION_EXTRA_RIGHT = 10;
+
+    //
     // Enumeration values for CaptureRequest#COLOR_CORRECTION_MODE
     //
 
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index a0fb179..60d5e9e 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3239,6 +3239,9 @@
      * with PRIMARY_CAMERA.</p>
      * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, this position cannot be accurately
      * represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p>
+     * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is AUTOMOTIVE, then this position is relative to the
+     * origin of the automotive sensor coordinate system, which is at the center of the rear
+     * axle.</p>
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
diff --git a/core/java/android/hardware/camera2/extension/ICaptureProcessorImpl.aidl b/core/java/android/hardware/camera2/extension/ICaptureProcessorImpl.aidl
index 022b084..3c5f5ff 100644
--- a/core/java/android/hardware/camera2/extension/ICaptureProcessorImpl.aidl
+++ b/core/java/android/hardware/camera2/extension/ICaptureProcessorImpl.aidl
@@ -17,6 +17,7 @@
 
 import android.view.Surface;
 import android.hardware.camera2.extension.CaptureBundle;
+import android.hardware.camera2.extension.IProcessResultImpl;
 import android.hardware.camera2.extension.Size;
 
 /** @hide */
@@ -25,5 +26,5 @@
     void onOutputSurface(in Surface surface, int imageFormat);
     void onResolutionUpdate(in Size size);
     void onImageFormatUpdate(int imageFormat);
-    void process(in List<CaptureBundle> capturelist);
+    void process(in List<CaptureBundle> capturelist, in IProcessResultImpl resultCallback);
 }
diff --git a/core/java/android/hardware/camera2/extension/IImageCaptureExtenderImpl.aidl b/core/java/android/hardware/camera2/extension/IImageCaptureExtenderImpl.aidl
index 3ebf637..a8a7866e 100644
--- a/core/java/android/hardware/camera2/extension/IImageCaptureExtenderImpl.aidl
+++ b/core/java/android/hardware/camera2/extension/IImageCaptureExtenderImpl.aidl
@@ -39,4 +39,6 @@
     int getMaxCaptureStage();
     @nullable List<SizeList> getSupportedResolutions();
     LatencyRange getEstimatedCaptureLatencyRange(in Size outputSize);
+    CameraMetadataNative getAvailableCaptureRequestKeys();
+    CameraMetadataNative getAvailableCaptureResultKeys();
 }
diff --git a/core/java/android/hardware/camera2/extension/IPreviewImageProcessorImpl.aidl b/core/java/android/hardware/camera2/extension/IPreviewImageProcessorImpl.aidl
index f7e4023..ecd098b 100644
--- a/core/java/android/hardware/camera2/extension/IPreviewImageProcessorImpl.aidl
+++ b/core/java/android/hardware/camera2/extension/IPreviewImageProcessorImpl.aidl
@@ -17,6 +17,7 @@
 
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.view.Surface;
+import android.hardware.camera2.extension.IProcessResultImpl;
 import android.hardware.camera2.extension.ParcelImage;
 import android.hardware.camera2.extension.Size;
 
@@ -26,5 +27,6 @@
     void onOutputSurface(in Surface surface, int imageFormat);
     void onResolutionUpdate(in Size size);
     void onImageFormatUpdate(int imageFormat);
-    void process(in ParcelImage image, in CameraMetadataNative result, int sequenceId);
+    void process(in ParcelImage image, in CameraMetadataNative result, int sequenceId,
+            in IProcessResultImpl resultCallback);
 }
diff --git a/core/java/android/net/DhcpResults.aidl b/core/java/android/hardware/camera2/extension/IProcessResultImpl.aidl
similarity index 65%
rename from core/java/android/net/DhcpResults.aidl
rename to core/java/android/hardware/camera2/extension/IProcessResultImpl.aidl
index f4db3c3..4114edb 100644
--- a/core/java/android/net/DhcpResults.aidl
+++ b/core/java/android/hardware/camera2/extension/IProcessResultImpl.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2012, The Android Open Source Project
+ * Copyright (c) 2022, 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.
@@ -13,7 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.hardware.camera2.extension;
 
-package android.net;
+import android.hardware.camera2.impl.CameraMetadataNative;
 
-parcelable DhcpResults;
+/** @hide */
+interface IProcessResultImpl
+{
+    void onCaptureCompleted(long shutterTimestamp, in CameraMetadataNative results);
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 9d2c901..cd392ce 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -105,7 +105,7 @@
     @RequiresPermission(android.Manifest.permission.CAMERA)
     public static CameraAdvancedExtensionSessionImpl createCameraAdvancedExtensionSession(
             @NonNull CameraDevice cameraDevice, @NonNull Context ctx,
-            @NonNull ExtensionSessionConfiguration config)
+            @NonNull ExtensionSessionConfiguration config, int sessionId)
             throws CameraAccessException, RemoteException {
         long clientId = CameraExtensionCharacteristics.registerClient(ctx);
         if (clientId < 0) {
@@ -135,6 +135,11 @@
                 throw new IllegalArgumentException("Unsupported dynamic range profile: " +
                         c.getDynamicRangeProfile());
             }
+            if (c.getStreamUseCase() !=
+                    CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+                throw new IllegalArgumentException("Unsupported stream use case: " +
+                        c.getStreamUseCase());
+            }
         }
 
         int suitableSurfaceCount = 0;
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 2920e67..87553d8 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -30,9 +30,11 @@
 import android.os.Handler;
 import android.os.ConditionVariable;
 import android.util.Range;
+import android.util.Log;
 import android.view.Surface;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -56,6 +58,7 @@
     private final CameraCharacteristics mCharacteristics;
     private final CameraCaptureSessionImpl mSessionImpl;
     private final ConditionVariable mInitialized = new ConditionVariable();
+    private final String TAG = "CameraConstrainedHighSpeedCaptureSessionImpl";
 
     /**
      * Create a new CameraCaptureSession.
@@ -95,10 +98,33 @@
         StreamConfigurationMap config = mCharacteristics.get(ck);
         SurfaceUtils.checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange, config);
 
-        // Request list size: to limit the preview to 30fps, need use maxFps/30; to maximize
-        // the preview frame rate, should use maxBatch size for that high speed stream
-        // configuration. We choose the former for now.
-        int requestListSize = fpsRange.getUpper() / 30;
+        // Check the high speed video fps ranges for video size and find the min value from the list
+        // and assign it to previewFps which will be used to calculate the requestList size.
+        Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRangesFor(
+                SurfaceUtils.getSurfaceSize(outputSurfaces.iterator().next()));
+        Log.v(TAG, "High speed fps ranges: " + Arrays.toString(highSpeedFpsRanges));
+        int previewFps = Integer.MAX_VALUE;
+        for (Range<Integer> range : highSpeedFpsRanges) {
+            int rangeMin = range.getLower();
+            if (previewFps > rangeMin) {
+                previewFps = rangeMin;
+            }
+        }
+        // Since we only want to support 60fps apart from 30fps, if the min value is not 60,
+        // then continue to calculate the requestList size using value 30.
+        if (previewFps != 60 && previewFps != 30) {
+            Log.w(TAG, "previewFps is neither 60 nor 30.");
+            previewFps = 30;
+        }
+        Log.v(TAG, "previewFps: " + previewFps);
+
+        int requestListSize = fpsRange.getUpper() / previewFps;
+        // If it's a preview, keep requestList size fixed = 1.
+        if (fpsRange.getUpper() > fpsRange.getLower()) {
+            requestListSize = 1;
+        }
+
+        Log.v(TAG, "Request list size is: " + requestListSize);
         List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
 
         // Prepare the Request builders: need carry over the request controls.
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 9b19fc4..3cb0c93 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -2495,10 +2495,10 @@
             if (CameraExtensionCharacteristics.areAdvancedExtensionsSupported()) {
                 mCurrentAdvancedExtensionSession =
                         CameraAdvancedExtensionSessionImpl.createCameraAdvancedExtensionSession(
-                                this, mContext, extensionConfiguration);
+                                this, mContext, extensionConfiguration, mNextSessionId++);
             } else {
                 mCurrentExtensionSession = CameraExtensionSessionImpl.createCameraExtensionSession(
-                        this, mContext, extensionConfiguration);
+                        this, mContext, extensionConfiguration, mNextSessionId++);
             }
         } catch (RemoteException e) {
             throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java
index bf45932..d148d87 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java
@@ -19,6 +19,7 @@
 import android.annotation.SuppressLint;
 import android.hardware.camera2.CameraExtensionCharacteristics;
 import android.hardware.camera2.extension.IPreviewImageProcessorImpl;
+import android.hardware.camera2.extension.IProcessResultImpl;
 import android.hardware.camera2.extension.ParcelImage;
 import android.hardware.camera2.TotalCaptureResult;
 import android.media.Image;
@@ -114,12 +115,12 @@
         }
     }
 
-    public void process(ParcelImage image, TotalCaptureResult totalCaptureResult)
-            throws RemoteException {
+    public void process(ParcelImage image, TotalCaptureResult totalCaptureResult,
+            IProcessResultImpl resultCallback) throws RemoteException {
         if ((mIntermediateSurface != null) && (mIntermediateSurface.isValid()) &&
                 !mOutputAbandoned) {
             mProcessor.process(image, totalCaptureResult.getNativeMetadata(),
-                    totalCaptureResult.getSequenceId());
+                    totalCaptureResult.getSequenceId(), resultCallback);
         }
     }
 
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
index 425f22c..1514a2b 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
@@ -24,6 +24,7 @@
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.extension.CaptureBundle;
 import android.hardware.camera2.extension.ICaptureProcessorImpl;
+import android.hardware.camera2.extension.IProcessResultImpl;
 import android.media.Image;
 import android.media.Image.Plane;
 import android.media.ImageReader;
@@ -183,11 +184,13 @@
             int cropLeft, int cropTop, int cropRight, int cropBottom,
             int rot90);
 
-    public void process(List<CaptureBundle> captureBundle) throws RemoteException {
+    @Override
+    public void process(List<CaptureBundle> captureBundle, IProcessResultImpl captureCallback)
+            throws RemoteException {
         JpegParameters jpegParams = getJpegParameters(captureBundle);
         try {
             mJpegParameters.add(jpegParams);
-            mProcessor.process(captureBundle);
+            mProcessor.process(captureBundle, captureCallback);
         } catch (Exception e) {
             mJpegParameters.remove(jpegParams);
             throw e;
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index c8ecfd0..a50db57 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -36,6 +36,7 @@
 import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
 import android.hardware.camera2.extension.IInitializeSessionCallback;
 import android.hardware.camera2.extension.IPreviewExtenderImpl;
+import android.hardware.camera2.extension.IProcessResultImpl;
 import android.hardware.camera2.extension.IRequestUpdateProcessorImpl;
 import android.hardware.camera2.extension.ParcelImage;
 import android.hardware.camera2.TotalCaptureResult;
@@ -67,6 +68,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 public final class CameraExtensionSessionImpl extends CameraExtensionSession {
@@ -83,6 +85,10 @@
     private final StateCallback mCallbacks;
     private final List<Size> mSupportedPreviewSizes;
     private final InitializeSessionHandler mInitializeHandler;
+    private final int mSessionId;
+    private final Set<CaptureRequest.Key> mSupportedRequestKeys;
+    private final Set<CaptureResult.Key> mSupportedResultKeys;
+    private boolean mCaptureResultsSupported;
 
     private CameraCaptureSession mCaptureSession = null;
     private Surface mCameraRepeatingSurface, mClientRepeatingRequestSurface;
@@ -121,7 +127,8 @@
     public static CameraExtensionSessionImpl createCameraExtensionSession(
             @NonNull CameraDevice cameraDevice,
             @NonNull Context ctx,
-            @NonNull ExtensionSessionConfiguration config)
+            @NonNull ExtensionSessionConfiguration config,
+            int sessionId)
             throws CameraAccessException, RemoteException {
         long clientId = CameraExtensionCharacteristics.registerClient(ctx);
         if (clientId < 0) {
@@ -151,6 +158,11 @@
                 throw new IllegalArgumentException("Unsupported dynamic range profile: " +
                         c.getDynamicRangeProfile());
             }
+            if (c.getStreamUseCase() !=
+                    CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+                throw new IllegalArgumentException("Unsupported stream use case: " +
+                        c.getStreamUseCase());
+            }
         }
 
         Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
@@ -197,7 +209,10 @@
                 repeatingRequestSurface,
                 burstCaptureSurface,
                 config.getStateCallback(),
-                config.getExecutor());
+                config.getExecutor(),
+                sessionId,
+                extensionChars.getAvailableCaptureRequestKeys(config.getExtension()),
+                extensionChars.getAvailableCaptureResultKeys(config.getExtension()));
 
         session.initialize();
 
@@ -212,7 +227,10 @@
             @Nullable Surface repeatingRequestSurface,
             @Nullable Surface burstCaptureSurface,
             @NonNull StateCallback callback,
-            @NonNull Executor executor) {
+            @NonNull Executor executor,
+            int sessionId,
+            @NonNull Set<CaptureRequest.Key> requestKeys,
+            @Nullable Set<CaptureResult.Key> resultKeys) {
         mExtensionClientId = extensionClientId;
         mImageExtender = imageExtender;
         mPreviewExtender = previewExtender;
@@ -227,6 +245,10 @@
         mHandler = new Handler(mHandlerThread.getLooper());
         mInitialized = false;
         mInitializeHandler = new InitializeSessionHandler();
+        mSessionId = sessionId;
+        mSupportedRequestKeys = requestKeys;
+        mSupportedResultKeys = resultKeys;
+        mCaptureResultsSupported = !resultKeys.isEmpty();
     }
 
     private void initializeRepeatingRequestPipeline() throws RemoteException {
@@ -483,7 +505,7 @@
         return captureStageList;
     }
 
-    private static List<CaptureRequest> createBurstRequest(CameraDevice cameraDevice,
+    private List<CaptureRequest> createBurstRequest(CameraDevice cameraDevice,
             List<CaptureStageImpl> captureStageList, CaptureRequest clientRequest,
             Surface target, int captureTemplate, Map<CaptureRequest, Integer> captureMap) {
         CaptureRequest.Builder requestBuilder;
@@ -495,16 +517,13 @@
                 return null;
             }
 
-            // This will override the extension capture stage jpeg parameters with the user set
-            // jpeg quality and rotation. This will guarantee that client configured jpeg
-            // parameters always have highest priority.
-            Integer jpegRotation = clientRequest.get(CaptureRequest.JPEG_ORIENTATION);
-            if (jpegRotation != null) {
-                captureStage.parameters.set(CaptureRequest.JPEG_ORIENTATION, jpegRotation);
-            }
-            Byte jpegQuality = clientRequest.get(CaptureRequest.JPEG_QUALITY);
-            if (jpegQuality != null) {
-                captureStage.parameters.set(CaptureRequest.JPEG_QUALITY, jpegQuality);
+            // This will guarantee that client configured
+            // parameters always have the highest priority.
+            for (CaptureRequest.Key requestKey : mSupportedRequestKeys){
+                Object value = clientRequest.get(requestKey);
+                if (value != null) {
+                    captureStage.parameters.set(requestKey, value);
+                }
             }
 
             requestBuilder.addTarget(target);
@@ -517,10 +536,9 @@
         return ret;
     }
 
-    private static CaptureRequest createRequest(CameraDevice cameraDevice,
-                                                List<CaptureStageImpl> captureStageList,
-                                                Surface target,
-                                                int captureTemplate) throws CameraAccessException {
+    private CaptureRequest createRequest(CameraDevice cameraDevice,
+            List<CaptureStageImpl> captureStageList, Surface target, int captureTemplate,
+            CaptureRequest clientRequest) throws CameraAccessException {
         CaptureRequest.Builder requestBuilder;
         requestBuilder = cameraDevice.createCaptureRequest(captureTemplate);
         if (target != null) {
@@ -528,14 +546,35 @@
         }
 
         CaptureRequest ret = requestBuilder.build();
+        CameraMetadataNative nativeMeta = ret.getNativeMetadata();
         for (CaptureStageImpl captureStage : captureStageList) {
             if (captureStage != null) {
-                CameraMetadataNative.update(ret.getNativeMetadata(), captureStage.parameters);
+                CameraMetadataNative.update(nativeMeta, captureStage.parameters);
             }
         }
+
+        if (clientRequest != null) {
+            // This will guarantee that client configured
+            // parameters always have the highest priority.
+            for (CaptureRequest.Key requestKey : mSupportedRequestKeys) {
+                Object value = clientRequest.get(requestKey);
+                if (value != null) {
+                    nativeMeta.set(requestKey, value);
+                }
+            }
+        }
+
         return ret;
     }
 
+    private CaptureRequest createRequest(CameraDevice cameraDevice,
+            List<CaptureStageImpl> captureStageList,
+            Surface target,
+            int captureTemplate) throws CameraAccessException {
+        return createRequest(cameraDevice, captureStageList, target, captureTemplate,
+                /*clientRequest*/ null);
+    }
+
     @Override
     public int capture(@NonNull CaptureRequest request,
                        @NonNull Executor executor,
@@ -629,12 +668,17 @@
     }
 
     private int setRepeatingRequest(CaptureStageImpl captureStage,
-                                    CameraCaptureSession.CaptureCallback requestHandler)
+            CameraCaptureSession.CaptureCallback requestHandler) throws CameraAccessException {
+        return setRepeatingRequest(captureStage, requestHandler, /*clientRequest*/ null);
+    }
+
+    private int setRepeatingRequest(CaptureStageImpl captureStage,
+            CameraCaptureSession.CaptureCallback requestHandler, CaptureRequest clientRequest)
             throws CameraAccessException {
         ArrayList<CaptureStageImpl> captureStageList = new ArrayList<>();
         captureStageList.add(captureStage);
-        CaptureRequest repeatingRequest = createRequest(mCameraDevice,
-                captureStageList, mCameraRepeatingSurface, CameraDevice.TEMPLATE_PREVIEW);
+        CaptureRequest repeatingRequest = createRequest(mCameraDevice, captureStageList,
+                mCameraRepeatingSurface, CameraDevice.TEMPLATE_PREVIEW, clientRequest);
         return mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
                 new CameraExtensionUtils.HandlerExecutor(mHandler), requestHandler);
     }
@@ -843,6 +887,7 @@
 
         private ImageCallback mImageCallback = null;
         private boolean mCaptureFailed = false;
+        private CaptureResultHandler mCaptureResultHandler = null;
 
         public BurstRequestHandler(@NonNull CaptureRequest request, @NonNull Executor executor,
                 @NonNull ExtensionCaptureCallback callbacks,
@@ -963,20 +1008,18 @@
 
             Long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
             if (timestamp != null) {
+                if (mCaptureResultsSupported && (mCaptureResultHandler == null)) {
+                    mCaptureResultHandler = new CaptureResultHandler(mClientRequest, mExecutor,
+                            mCallbacks, result.getSessionId());
+                }
                 if (mImageProcessor != null) {
                     if (mCapturePendingMap.indexOfKey(timestamp) >= 0) {
                         Image img = mCapturePendingMap.get(timestamp).first;
-                        mCaptureStageMap.put(stageId,
-                                new Pair<>(img,
-                                        result));
+                        mCaptureStageMap.put(stageId, new Pair<>(img, result));
                         checkAndFireBurstProcessing();
                     } else {
-                        mCapturePendingMap.put(timestamp,
-                                new Pair<>(null,
-                                        stageId));
-                        mCaptureStageMap.put(stageId,
-                                new Pair<>(null,
-                                        result));
+                        mCapturePendingMap.put(timestamp, new Pair<>(null, stageId));
+                        mCaptureStageMap.put(stageId, new Pair<>(null, result));
                     }
                 } else {
                     mCaptureRequestMap.clear();
@@ -986,6 +1029,18 @@
                                 () -> mCallbacks
                                         .onCaptureProcessStarted(CameraExtensionSessionImpl.this,
                                                 mClientRequest));
+
+                        if (mCaptureResultHandler != null) {
+                            CameraMetadataNative captureResults = new CameraMetadataNative();
+                            for (CaptureResult.Key key : mSupportedResultKeys) {
+                                Object value = result.get(key);
+                                if (value != null) {
+                                    captureResults.set(key, value);
+                                }
+                            }
+                            mCaptureResultHandler.onCaptureCompleted(timestamp,
+                                    captureResults);
+                        }
                     } finally {
                         Binder.restoreCallingIdentity(ident);
                     }
@@ -1013,7 +1068,7 @@
                 List<CaptureBundle> captureList = initializeParcelable(mCaptureStageMap,
                         jpegOrientation, jpegQuality);
                 try {
-                    mImageProcessor.process(captureList);
+                    mImageProcessor.process(captureList, mCaptureResultHandler);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to process multi-frame request! Extension service "
                             + "does not respond!");
@@ -1228,6 +1283,43 @@
         }
     }
 
+    private class CaptureResultHandler extends IProcessResultImpl.Stub {
+        private final Executor mExecutor;
+        private final ExtensionCaptureCallback mCallbacks;
+        private final CaptureRequest mClientRequest;
+        private final int mRequestId;
+
+        public CaptureResultHandler(@NonNull CaptureRequest clientRequest,
+                @NonNull Executor executor, @NonNull ExtensionCaptureCallback listener,
+                int requestId) {
+            mClientRequest = clientRequest;
+            mExecutor = executor;
+            mCallbacks = listener;
+            mRequestId = requestId;
+        }
+
+        @Override
+        public void onCaptureCompleted(long shutterTimestamp, CameraMetadataNative result) {
+            if (result == null) {
+                Log.e(TAG,"Invalid capture result!");
+                return;
+            }
+
+            result.set(CaptureResult.SENSOR_TIMESTAMP, shutterTimestamp);
+            TotalCaptureResult totalResult = new TotalCaptureResult(mCameraDevice.getId(), result,
+                    mClientRequest, mRequestId, shutterTimestamp, new ArrayList<CaptureResult>(),
+                    mSessionId, new PhysicalCaptureResultInfo[0]);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(
+                        () -> mCallbacks.onCaptureResultAvailable(CameraExtensionSessionImpl.this,
+                                mClientRequest, totalResult));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
     // This handler can operate in two modes:
     // 1) Using valid client callbacks, which means camera buffers will be propagated the
     //    registered output surfaces and clients will be notified accordingly.
@@ -1242,6 +1334,7 @@
         private OnImageAvailableListener mImageCallback = null;
         private LongSparseArray<Pair<Image, TotalCaptureResult>> mPendingResultMap =
                 new LongSparseArray<>();
+        private CaptureResultHandler mCaptureResultHandler = null;
 
         private boolean mRequestUpdatedNeeded = false;
 
@@ -1375,6 +1468,11 @@
             synchronized (mInterfaceLock) {
                 final Long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
                 if (timestamp != null) {
+                    if (mCaptureResultsSupported && mClientNotificationsEnabled &&
+                            (mCaptureResultHandler == null)) {
+                        mCaptureResultHandler = new CaptureResultHandler(mClientRequest, mExecutor,
+                                mCallbacks, result.getSessionId());
+                    }
                     if (mPreviewProcessorType ==
                             IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY) {
                         CaptureStageImpl captureStage = null;
@@ -1387,7 +1485,7 @@
                         }
                         if (captureStage != null) {
                             try {
-                                setRepeatingRequest(captureStage, this);
+                                setRepeatingRequest(captureStage, this, request);
                                 mRequestUpdatedNeeded = true;
                             } catch (IllegalStateException e) {
                                 // This is possible in case the camera device closes and the
@@ -1406,7 +1504,8 @@
                             ParcelImage parcelImage = initializeParcelImage(
                                     mPendingResultMap.get(timestamp).first);
                             try {
-                                mPreviewImageProcessor.process(parcelImage, result);
+                                mPreviewImageProcessor.process(parcelImage, result,
+                                        mCaptureResultHandler);
                             } catch (RemoteException e) {
                                 processStatus = false;
                                 Log.e(TAG, "Extension service does not respond during " +
@@ -1444,6 +1543,19 @@
                                         .onCaptureProcessStarted(
                                                 CameraExtensionSessionImpl.this,
                                                 mClientRequest));
+                                if ((mCaptureResultHandler != null) && (mPreviewProcessorType !=
+                                        IPreviewExtenderImpl.PROCESSOR_TYPE_IMAGE_PROCESSOR)) {
+                                    CameraMetadataNative captureResults =
+                                            new CameraMetadataNative();
+                                    for (CaptureResult.Key key : mSupportedResultKeys) {
+                                        Object value = result.get(key);
+                                        if (value != null) {
+                                            captureResults.set(key, value);
+                                        }
+                                    }
+                                    mCaptureResultHandler.onCaptureCompleted(timestamp,
+                                            captureResults);
+                                }
                             } else {
                                 mExecutor.execute(
                                         () -> mCallbacks
@@ -1587,7 +1699,7 @@
                     ParcelImage parcelImage = initializeParcelImage(img);
                     try {
                         mPreviewImageProcessor.process(parcelImage,
-                                mPendingResultMap.get(timestamp).second);
+                                mPendingResultMap.get(timestamp).second, mCaptureResultHandler);
                     } catch (RemoteException e) {
                         processStatus = false;
                         Log.e(TAG, "Extension service does not respond during " +
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 0f8bdf6..9b67633 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -333,6 +333,7 @@
     private static final int MANDATORY_STREAM_CONFIGURATIONS_MAX_RESOLUTION = 1;
     private static final int MANDATORY_STREAM_CONFIGURATIONS_CONCURRENT = 2;
     private static final int MANDATORY_STREAM_CONFIGURATIONS_10BIT = 3;
+    private static final int MANDATORY_STREAM_CONFIGURATIONS_USE_CASE = 4;
 
     private static String translateLocationProviderToProcess(final String provider) {
         if (provider == null) {
@@ -700,6 +701,16 @@
                 });
 
         sGetCommandMap.put(
+                CameraCharacteristics.SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS.getNativeKey(),
+                        new GetCommand() {
+                    @Override
+                    @SuppressWarnings("unchecked")
+                    public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+                        return (T) metadata.getMandatoryUseCaseStreamCombinations();
+                    }
+                });
+
+        sGetCommandMap.put(
                 CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
                     @Override
                     @SuppressWarnings("unchecked")
@@ -1413,6 +1424,9 @@
             case MANDATORY_STREAM_CONFIGURATIONS_10BIT:
                 combs = build.getAvailableMandatory10BitStreamCombinations();
                 break;
+            case MANDATORY_STREAM_CONFIGURATIONS_USE_CASE:
+                combs = build.getAvailableMandatoryStreamUseCaseCombinations();
+                break;
             default:
                 combs = build.getAvailableMandatoryStreamCombinations();
         }
@@ -1446,6 +1460,10 @@
         return getMandatoryStreamCombinationsHelper(MANDATORY_STREAM_CONFIGURATIONS_DEFAULT);
     }
 
+    private MandatoryStreamCombination[] getMandatoryUseCaseStreamCombinations() {
+        return getMandatoryStreamCombinationsHelper(MANDATORY_STREAM_CONFIGURATIONS_USE_CASE);
+    }
+
     private StreamConfigurationMap getStreamConfigurationMap() {
         StreamConfiguration[] configurations = getBase(
                 CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 32c15da..0d93c98 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -26,6 +26,9 @@
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.OutputConfiguration.StreamUseCase;
+import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.HashCodeHelpers;
 import android.media.CamcorderProfile;
 import android.util.Log;
@@ -63,6 +66,7 @@
         private final boolean mIsUltraHighResolution;
         private final boolean mIsMaximumSize;
         private final boolean mIs10BitCapable;
+        private final int mStreamUseCase;
 
         /**
          * Create a new {@link MandatoryStreamInformation}.
@@ -141,6 +145,30 @@
         public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
                 boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
                 boolean is10BitCapable) {
+            this(availableSizes, format, isMaximumSize, isInput, isUltraHighResolution,
+                    is10BitCapable, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
+        }
+
+        /**
+         * Create a new {@link MandatoryStreamInformation}.
+         *
+         * @param availableSizes List of possible stream sizes.
+         * @param format Image format.
+         * @param isMaximumSize Whether this is a maximum size stream.
+         * @param isInput Flag indicating whether this stream is input.
+         * @param isUltraHighResolution Flag indicating whether this is a ultra-high resolution
+         *                              stream.
+         * @param is10BitCapable Flag indicating whether this stream is able to support 10-bit
+         * @param streamUseCase The stream use case.
+         *
+         * @throws IllegalArgumentException
+         *              if sizes is empty or if the format was not user-defined in
+         *              ImageFormat/PixelFormat.
+         * @hide
+         */
+        public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
+                boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
+                boolean is10BitCapable, @StreamUseCase int streamUseCase) {
             if (availableSizes.isEmpty()) {
                 throw new IllegalArgumentException("No available sizes");
             }
@@ -150,6 +178,7 @@
             mIsInput = isInput;
             mIsUltraHighResolution = isUltraHighResolution;
             mIs10BitCapable = is10BitCapable;
+            mStreamUseCase = streamUseCase;
         }
 
         /**
@@ -272,6 +301,20 @@
         }
 
         /**
+         * Retrieve the mandatory stream use case.
+         *
+         * <p>If this {@link MandatoryStreamInformation} is part of a mandatory stream
+         * combination for stream use cases, the return value will be a non-DEFAULT value.
+         * For {@link MandatoryStreamInformation} belonging to other mandatory stream
+         * combinations, the return value will be DEFAULT. </p>
+         *
+         * @return the integer stream use case.
+         */
+        public @StreamUseCase int getStreamUseCase() {
+            return mStreamUseCase;
+        }
+
+        /**
          * Check if this {@link MandatoryStreamInformation} is equal to another
          * {@link MandatoryStreamInformation}.
          *
@@ -292,6 +335,7 @@
                 final MandatoryStreamInformation other = (MandatoryStreamInformation) obj;
                 if ((mFormat != other.mFormat) || (mIsInput != other.mIsInput) ||
                         (mIsUltraHighResolution != other.mIsUltraHighResolution) ||
+                        (mStreamUseCase != other.mStreamUseCase) ||
                         (mAvailableSizes.size() != other.mAvailableSizes.size())) {
                     return false;
                 }
@@ -308,7 +352,8 @@
         @Override
         public int hashCode() {
             return HashCodeHelpers.hashCode(mFormat, Boolean.hashCode(mIsInput),
-                    Boolean.hashCode(mIsUltraHighResolution), mAvailableSizes.hashCode());
+                    Boolean.hashCode(mIsUltraHighResolution), mAvailableSizes.hashCode(),
+                    mStreamUseCase);
         }
     }
 
@@ -316,6 +361,21 @@
     private final boolean mIsReprocessable;
     private final ArrayList<MandatoryStreamInformation> mStreamsInformation =
             new ArrayList<MandatoryStreamInformation>();
+
+    /**
+     * Short hand for stream use cases
+     */
+    private static final int STREAM_USE_CASE_PREVIEW =
+            CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW;
+    private static final int STREAM_USE_CASE_STILL_CAPTURE =
+            CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE;
+    private static final int STREAM_USE_CASE_RECORD =
+            CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD;
+    private static final int STREAM_USE_CASE_PREVIEW_VIDEO_STILL =
+            CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL;
+    private static final int STREAM_USE_CASE_VIDEO_CALL =
+            CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+
     /**
      * Create a new {@link MandatoryStreamCombination}.
      *
@@ -411,15 +471,15 @@
     private static final class StreamTemplate {
         public int mFormat;
         public SizeThreshold mSizeThreshold;
-        public boolean mIsInput;
+        public int mStreamUseCase;
         public StreamTemplate(int format, SizeThreshold sizeThreshold) {
-            this(format, sizeThreshold, /*isInput*/false);
+            this(format, sizeThreshold, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
         }
         public StreamTemplate(@Format int format, @NonNull SizeThreshold sizeThreshold,
-                boolean isInput) {
+                @StreamUseCase int streamUseCase) {
             mFormat = format;
             mSizeThreshold = sizeThreshold;
-            mIsInput = isInput;
+            mStreamUseCase = streamUseCase;
         }
     }
 
@@ -1034,6 +1094,174 @@
                     "High-resolution recording with video snapshot"),
     };
 
+    private static StreamCombinationTemplate sStreamUseCaseCombinations[] = {
+        // Single stream combinations
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW) },
+                "Simple preview"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW) },
+                "Simple in-application image processing"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_RECORD) },
+                "Simple video recording"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_RECORD) },
+                "Simple in-application video processing"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE) },
+                "Simple JPEG still capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE) },
+                "Simple YUV still capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_PREVIEW_VIDEO_STILL) },
+                "Multi-purpose stream for preview, video and still capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_PREVIEW_VIDEO_STILL) },
+                "Multi-purpose YUV stream for preview, video and still capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_VIDEO_CALL) },
+                "Simple video call"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_VIDEO_CALL) },
+                "Simple YUV video call"),
+
+        // 2-stream combinations
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Preview with JPEG still image capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Preview with YUV still image capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_RECORD)},
+                "Preview with video recording"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_RECORD)},
+                "Preview with in-application video processing"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW)},
+                "Preview with in-application image processing"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_VIDEO_CALL)},
+                "Preview with video call"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_VIDEO_CALL)},
+                "Preview with YUV video call"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Multi-purpose stream with JPEG still capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Multi-purpose stream with YUV still capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Multi-purpose YUV stream with JPEG still capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+                        STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Multi-purpose YUV stream with YUV still capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_STILL_CAPTURE),
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "YUV and JPEG concurrent still image capture (for testing)"),
+
+        // 3-stream combinations
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_RECORD),
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Preview, video record and JPEG video snapshot"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_RECORD),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Preview, video record and YUV video snapshot"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_RECORD),
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Preview, in-application video processing and JPEG video snapshot"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_RECORD),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Preview, in-application video processing and YUV video snapshot"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Preview, in-application image processing, and JPEG still image capture"),
+        new StreamCombinationTemplate(new StreamTemplate [] {
+                new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+                        STREAM_USE_CASE_PREVIEW),
+                new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+                        STREAM_USE_CASE_STILL_CAPTURE)},
+                "Preview, in-application image processing, and YUV still image capture"),
+    };
+
     /**
      * Helper builder class to generate a list of available mandatory stream combinations.
      * @hide
@@ -1153,6 +1381,76 @@
         }
 
         /**
+          * Retrieve a list of all available mandatory stream combinations with stream use cases.
+          * when the camera device has {@link
+          * CameraMetdata.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE} capability.
+          *
+          * @return a non-modifiable list of supported mandatory stream combinations with stream
+          *         use cases. Null in case the device doesn't have {@link
+          *         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}
+          *         capability.
+          */
+        public @NonNull List<MandatoryStreamCombination>
+                getAvailableMandatoryStreamUseCaseCombinations() {
+            if (!isCapabilitySupported(
+                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE)) {
+                return null;
+            }
+
+            HashMap<Pair<SizeThreshold, Integer>, List<Size>> availableSizes =
+                    enumerateAvailableSizes();
+            if (availableSizes == null) {
+                Log.e(TAG, "Available size enumeration failed!");
+                return null;
+            }
+
+            ArrayList<MandatoryStreamCombination> availableStreamCombinations = new ArrayList<>();
+            availableStreamCombinations.ensureCapacity(sStreamUseCaseCombinations.length);
+            for (StreamCombinationTemplate combTemplate : sStreamUseCaseCombinations) {
+                ArrayList<MandatoryStreamInformation> streamsInfo =
+                        new ArrayList<MandatoryStreamInformation>();
+                streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
+
+                for (StreamTemplate template : combTemplate.mStreamTemplates) {
+                    List<Size> sizes = null;
+                    Pair<SizeThreshold, Integer> pair;
+                    pair = new Pair<SizeThreshold, Integer>(template.mSizeThreshold,
+                            new Integer(template.mFormat));
+                    sizes = availableSizes.get(pair);
+
+                    MandatoryStreamInformation streamInfo;
+                    boolean isMaximumSize =
+                            (template.mSizeThreshold == SizeThreshold.MAXIMUM);
+                    try {
+                        streamInfo = new MandatoryStreamInformation(sizes, template.mFormat,
+                                isMaximumSize, /*isInput*/false, /*isUltraHighResolution*/false,
+                                /*is10BitCapable*/ false, template.mStreamUseCase);
+                    } catch (IllegalArgumentException e) {
+                        Log.e(TAG, "No available sizes found for format: " + template.mFormat +
+                                " size threshold: " + template.mSizeThreshold + " combination: " +
+                                combTemplate.mDescription);
+                        return null;
+                    }
+                    streamsInfo.add(streamInfo);
+                }
+
+                MandatoryStreamCombination streamCombination;
+                try {
+                    streamCombination = new MandatoryStreamCombination(streamsInfo,
+                            combTemplate.mDescription, /*isReprocessable*/ false);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, "No stream information for mandatory combination: "
+                            + combTemplate.mDescription);
+                    return null;
+                }
+
+                availableStreamCombinations.add(streamCombination);
+            }
+
+            return Collections.unmodifiableList(availableStreamCombinations);
+        }
+
+        /**
           * Retrieve a list of all available mandatory concurrent stream combinations.
           * This method should only be called for devices which are listed in combinations returned
           * by CameraManager.getConcurrentCameraIds.
@@ -1632,6 +1930,8 @@
             Size recordingMaxSize = new Size(0, 0);
             Size previewMaxSize = new Size(0, 0);
             Size vgaSize = new Size(640, 480);
+            Size s720pSize = new Size(1280, 720);
+            Size s1440pSize = new Size(1920, 1440);
             // For external camera, or hidden physical camera, CamcorderProfile may not be
             // available, so get maximum recording size using stream configuration map.
             if (isExternalCamera() || mIsHiddenPhysicalCamera) {
@@ -1682,6 +1982,12 @@
 
                 pair = new Pair<SizeThreshold, Integer>(SizeThreshold.MAXIMUM, intFormat);
                 availableSizes.put(pair, Arrays.asList(sizes));
+
+                pair = new Pair<SizeThreshold, Integer>(SizeThreshold.s720p, intFormat);
+                availableSizes.put(pair, getSizesWithinBound(sizes, s720pSize));
+
+                pair = new Pair<SizeThreshold, Integer>(SizeThreshold.s1440p, intFormat);
+                availableSizes.put(pair, getSizesWithinBound(sizes, s1440pSize));
             }
 
             return availableSizes;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index f2b881b..d8295c9 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -159,6 +159,17 @@
           CameraMetadata.SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION})
      public @interface SensorPixelMode {};
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"STREAM_USE_CASE_"}, value =
+        {CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+         CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW,
+         CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE,
+         CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD,
+         CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL,
+         CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL})
+    public @interface StreamUseCase {};
+
     /**
      * Create a new {@link OutputConfiguration} instance with a {@link Surface}.
      *
@@ -355,6 +366,7 @@
         mIsMultiResolution = false;
         mSensorPixelModesUsed = new ArrayList<Integer>();
         mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+        mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
     }
 
     /**
@@ -453,6 +465,7 @@
         mIsMultiResolution = false;
         mSensorPixelModesUsed = new ArrayList<Integer>();
         mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+        mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
     }
 
     /**
@@ -730,6 +743,73 @@
     }
 
     /**
+     * Set stream use case for this OutputConfiguration
+     *
+     * <p>Stream use case is used to describe the purpose of the stream, whether it's for live
+     * preview, still image capture, video recording, or their combinations. This flag is useful
+     * for scenarios where the immediate consumer target isn't sufficient to indicate the stream's
+     * usage.</p>
+     *
+     * <p>The main difference beteween stream use case and capture intent is that the former
+     * enables the camera device to optimize camera hardware and software pipelines based on user
+     * scenarios for each stream, whereas the latter is mainly a hint to camera to decide
+     * optimal 3A strategy that's applicable to the whole session. The camera device carries out
+     * configurations such as selecting tuning parameters, choosing camera sensor mode, and
+     * constructing image processing pipeline based on the streams's use cases. Capture intents are
+     * then used to fine tune 3A behaviors such as adjusting AE/AF convergence speed, and capture
+     * intents may change during the lifetime of a session. For example, for a session with a
+     * PREVIEW_VIDEO_STILL use case stream and a STILL_CAPTURE use case stream, the capture intents
+     * may be PREVIEW with fast 3A convergence speed and flash metering with automatic control for
+     * live preview, STILL_CAPTURE with best 3A parameters for still photo capture, or VIDEO_RECORD
+     * with slower 3A convergence speed for better video playback experience.</p>
+     *
+     * <p>The supported stream use cases supported by a camera device can be queried by
+     * {@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES}.</p>
+     *
+     * <p>The mandatory stream combinations involving stream use cases can be found at {@link
+     * android.hardware.camera2.CameraDevice#createCaptureSession}, as well as queried via
+     * {@link android.hardware.camera2.params.MandatoryStreamCombination}. The application is
+     * strongly recommended to select one of the guaranteed stream combinations where all streams'
+     * use cases are set to non-DEFAULT values. If the application chooses a stream combination
+     * not in the mandatory list, the camera device may ignore some use case flags due to
+     * hardware constraints or implementation details.</p>
+     *
+     * <p>This function must be called before {@link CameraDevice#createCaptureSession} or {@link
+     * CameraDevice#createCaptureSessionByOutputConfigurations}. Calling this function after
+     * {@link CameraDevice#createCaptureSession} or
+     * {@link CameraDevice#createCaptureSessionByOutputConfigurations} has no effect to the camera
+     * session.</p>
+     *
+     * @param streamUseCase The stream use case to be set.
+     *
+     * @throws IllegalArgumentException If the streamUseCase isn't within the range of valid
+     *                                  values.
+     */
+    public void setStreamUseCase(@StreamUseCase int streamUseCase) {
+        // Verify that the value is in range
+        int maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+        if (streamUseCase > maxUseCaseValue &&
+                streamUseCase < CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START) {
+            throw new IllegalArgumentException("Not a valid stream use case value " +
+                    streamUseCase);
+        }
+
+        mStreamUseCase = streamUseCase;
+    }
+
+    /**
+     * Get the current stream use case
+     *
+     * <p>If no {@link #setStreamUseCase} is called first, this function returns
+     * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT DEFAULT}.</p>
+     *
+     * @return the currently set stream use case
+     */
+    public int getStreamUseCase() {
+        return mStreamUseCase;
+    }
+
+    /**
      * Create a new {@link OutputConfiguration} instance with another {@link OutputConfiguration}
      * instance.
      *
@@ -756,6 +836,7 @@
         this.mIsMultiResolution = other.mIsMultiResolution;
         this.mSensorPixelModesUsed = other.mSensorPixelModesUsed;
         this.mDynamicRangeProfile = other.mDynamicRangeProfile;
+        this.mStreamUseCase = other.mStreamUseCase;
     }
 
     /**
@@ -774,6 +855,8 @@
         String physicalCameraId = source.readString();
         boolean isMultiResolutionOutput = source.readInt() == 1;
         int[] sensorPixelModesUsed = source.createIntArray();
+        int streamUseCase = source.readInt();
+
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
         int dynamicRangeProfile = source.readInt();
         DynamicRangeProfiles.checkProfileValue(dynamicRangeProfile);
@@ -801,6 +884,7 @@
         mIsMultiResolution = isMultiResolutionOutput;
         mSensorPixelModesUsed = convertIntArrayToIntegerList(sensorPixelModesUsed);
         mDynamicRangeProfile = dynamicRangeProfile;
+        mStreamUseCase = streamUseCase;
     }
 
     /**
@@ -917,6 +1001,7 @@
         // writeList doesn't seem to work well with Integer list.
         dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed));
         dest.writeInt(mDynamicRangeProfile);
+        dest.writeInt(mStreamUseCase);
     }
 
     /**
@@ -947,7 +1032,8 @@
                     mConfiguredDataspace != other.mConfiguredDataspace ||
                     mConfiguredGenerationId != other.mConfiguredGenerationId ||
                     !Objects.equals(mPhysicalCameraId, other.mPhysicalCameraId) ||
-                    mIsMultiResolution != other.mIsMultiResolution)
+                    mIsMultiResolution != other.mIsMultiResolution ||
+                    mStreamUseCase != other.mStreamUseCase)
                 return false;
             if (mSensorPixelModesUsed.size() != other.mSensorPixelModesUsed.size()) {
                 return false;
@@ -985,7 +1071,7 @@
                     mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
                     mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
                     mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
-                    mDynamicRangeProfile);
+                    mDynamicRangeProfile, mStreamUseCase);
         }
 
         return HashCodeHelpers.hashCode(
@@ -994,7 +1080,7 @@
                 mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
                 mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
                 mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
-                mDynamicRangeProfile);
+                mDynamicRangeProfile, mStreamUseCase);
     }
 
     private static final String TAG = "OutputConfiguration";
@@ -1028,4 +1114,6 @@
     private ArrayList<Integer> mSensorPixelModesUsed;
     // Dynamic range profile
     private int mDynamicRangeProfile;
+    // Stream use case
+    private int mStreamUseCase;
 }
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index cc9aeab..3f20002 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -87,6 +87,12 @@
      */
     public abstract void setVirtualMousePointerDisplayId(int pointerDisplayId);
 
+    /**
+     * Gets the display id that the MouseCursorController is being forced to target. Returns
+     * {@link android.view.Display#INVALID_DISPLAY} if there is no override
+     */
+    public abstract int getVirtualMousePointerDisplayId();
+
     /** Gets the current position of the mouse cursor. */
     public abstract PointF getCursorPosition();
 
@@ -94,7 +100,7 @@
      * Sets the pointer acceleration.
      * See {@code frameworks/native/include/input/VelocityControl.h#VelocityControlParameters}.
      */
-    public abstract void setPointerAcceleration(float acceleration);
+    public abstract void setPointerAcceleration(float acceleration, int displayId);
 
     /**
      * Sets the eligibility of windows on a given display for pointer capture. If a display is
@@ -103,6 +109,9 @@
      */
     public abstract void setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible);
 
+    /** Sets the visibility of the cursor. */
+    public abstract void setPointerIconVisible(boolean visible, int displayId);
+
     /** Registers the {@link LidSwitchCallback} to begin receiving notifications. */
     public abstract void registerLidSwitchCallback(@NonNull LidSwitchCallback callbacks);
 
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
index dbe7a41..c311379 100644
--- a/core/java/android/hardware/lights/Light.java
+++ b/core/java/android/hardware/lights/Light.java
@@ -38,6 +38,12 @@
     /** Type for lights that indicate microphone usage */
     public static final int LIGHT_TYPE_MICROPHONE = 8;
 
+    /** Type for lights that indicate camera usage
+     *
+     * @hide
+     */
+    public static final int LIGHT_TYPE_CAMERA = 9;
+
     // These enum values start from 10001 to avoid collision with expanding of HAL light types.
     /**
      * Type for lights that indicate a monochrome color LED light.
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index fc2fbc3..b6e1b1f 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -839,10 +839,9 @@
             final boolean wasVisible = isInputViewShown();
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
 
-            applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */);
             mShowInputFlags = 0;
             mShowInputRequested = false;
-            doHideWindow();
+            hideWindow();
             final boolean isVisible = isInputViewShown();
             final boolean visibilityChanged = isVisible != wasVisible;
             if (resultReceiver != null) {
@@ -891,7 +890,6 @@
             final boolean wasVisible = isInputViewShown();
             if (dispatchOnShowInputRequested(flags, false)) {
                 showWindow(true);
-                applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */);
             }
             setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
 
@@ -1666,7 +1664,7 @@
                         onDisplayCompletions(completions);
                     }
                 } else {
-                    doHideWindow();
+                    hideWindow();
                 }
             } else if (mCandidatesVisibility == View.VISIBLE) {
                 // If the candidates are currently visible, make sure the
@@ -1674,7 +1672,7 @@
                 showWindow(false);
             } else {
                 // Otherwise hide the window.
-                doHideWindow();
+                hideWindow();
             }
             // If user uses hard keyboard, IME button should always be shown.
             boolean showing = onEvaluateInputViewShown();
@@ -2119,7 +2117,7 @@
             if (shown) {
                 showWindow(false);
             } else {
-                doHideWindow();
+                hideWindow();
             }
         }
     }
@@ -2540,12 +2538,11 @@
         mWindowVisible = true;
 
         // request draw for the IME surface.
-        // When IME is not pre-rendered, this will actually show the IME.
-        if ((previousImeWindowStatus & IME_ACTIVE) == 0) {
-            if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
-            mWindow.show();
-        }
+        if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
+        mWindow.show();
         mDecorViewWasVisible = true;
+        applyVisibilityInInsetsConsumerIfNecessary(true);
+        cancelImeSurfaceRemoval();
         mInShowWindow = false;
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
@@ -2602,9 +2599,6 @@
         ImeTracing.getInstance().triggerServiceDump(
                 "InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper,
                 null /* icProto */);
-        if (setVisible) {
-            cancelImeSurfaceRemoval();
-        }
         mPrivOps.applyImeVisibilityAsync(setVisible
                 ? mCurShowInputToken : mCurHideInputToken, setVisible);
     }
@@ -2622,15 +2616,12 @@
         mCandidatesViewStarted = false;
     }
 
-    private void doHideWindow() {
-        setImeWindowStatus(0, mBackDisposition);
-        hideWindow();
-    }
-
     public void hideWindow() {
         if (DEBUG) Log.v(TAG, "CALL: hideWindow");
         ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
                 null /* icProto */);
+        setImeWindowStatus(0, mBackDisposition);
+        applyVisibilityInInsetsConsumerIfNecessary(false);
         mWindowVisible = false;
         finishViews(false /* finishingInput */);
         if (mDecorViewVisible) {
@@ -2916,7 +2907,7 @@
                 // If we have the window visible for some other reason --
                 // most likely to show candidates -- then just get rid
                 // of it.  This really shouldn't happen, but just in case...
-                if (doIt) doHideWindow();
+                if (doIt) hideWindow();
             }
             return true;
         }
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index e5c22e4..6f4fd76 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -219,7 +219,7 @@
                     // TODO(b/213337792): Set NAVIGATION_HINT_IME_SHOWN only when necessary.
                     final int hints = StatusBarManager.NAVIGATION_HINT_BACK_ALT
                             | (mShouldShowImeSwitcherWhenImeIsShown
-                                    ? StatusBarManager.NAVIGATION_HINT_IME_SHOWN
+                                    ? StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN
                                     : 0);
                     navigationBarView.setNavigationIconHints(hints);
                 }
@@ -470,7 +470,7 @@
             }
             final int hints = StatusBarManager.NAVIGATION_HINT_BACK_ALT
                     | (shouldShowImeSwitcherWhenImeIsShown
-                    ? StatusBarManager.NAVIGATION_HINT_IME_SHOWN : 0);
+                    ? StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN : 0);
             navigationBarView.setNavigationIconHints(hints);
         }
 
@@ -531,12 +531,14 @@
 
             if (drawLegacyNavigationBarBackground != mDrawLegacyNavigationBarBackground) {
                 mDrawLegacyNavigationBarBackground = drawLegacyNavigationBarBackground;
-                if (mDrawLegacyNavigationBarBackground) {
-                    mNavigationBarFrame.setBackgroundColor(Color.BLACK);
-                } else {
-                    mNavigationBarFrame.setBackground(null);
+                if (mNavigationBarFrame != null) {
+                    if (mDrawLegacyNavigationBarBackground) {
+                        mNavigationBarFrame.setBackgroundColor(Color.BLACK);
+                    } else {
+                        mNavigationBarFrame.setBackground(null);
+                    }
+                    scheduleRelayout();
                 }
-                scheduleRelayout();
                 onSystemBarAppearanceChanged(mAppearance);
             }
             return drawLegacyNavigationBarBackground;
@@ -546,7 +548,8 @@
         public String toDebugString() {
             return "{mRenderGesturalNavButtons=" + mRenderGesturalNavButtons
                     + " mNavigationBarFrame=" + mNavigationBarFrame
-                    + " mShouldShowImeSwitcherWhenImeIsShown" + mShouldShowImeSwitcherWhenImeIsShown
+                    + " mShouldShowImeSwitcherWhenImeIsShown="
+                    + mShouldShowImeSwitcherWhenImeIsShown
                     + " mAppearance=0x" + Integer.toHexString(mAppearance)
                     + " mDarkIntensity=" + mDarkIntensity
                     + " mDrawLegacyNavigationBarBackground=" + mDrawLegacyNavigationBarBackground
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
index 4284778..a2d7105 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
@@ -270,7 +270,7 @@
 
         // Update IME button visibility, a11y and rotate button always overrides the appearance
         final boolean imeSwitcherVisible =
-                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0;
+                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN) != 0;
         getImeSwitchButton().setVisibility(imeSwitcherVisible ? View.VISIBLE : View.INVISIBLE);
 
         getBackButton().setVisibility(View.VISIBLE);
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
deleted file mode 100644
index 82ba156..0000000
--- a/core/java/android/net/DhcpResults.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.net.module.util.InetAddressUtils;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * A simple object for retrieving the results of a DHCP request.
- * Optimized (attempted) for that jni interface
- * TODO: remove this class and replace with other existing constructs
- * @hide
- */
-public final class DhcpResults implements Parcelable {
-    private static final String TAG = "DhcpResults";
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public LinkAddress ipAddress;
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public InetAddress gateway;
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public final ArrayList<InetAddress> dnsServers = new ArrayList<>();
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public String domains;
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public Inet4Address serverAddress;
-
-    /** Vendor specific information (from RFC 2132). */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public String vendorInfo;
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public int leaseDuration;
-
-    /** Link MTU option. 0 means unset. */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public int mtu;
-
-    public String serverHostName;
-
-    @Nullable
-    public String captivePortalApiUrl;
-
-    public DhcpResults() {
-        super();
-    }
-
-    /**
-     * Create a {@link StaticIpConfiguration} based on the DhcpResults.
-     */
-    public StaticIpConfiguration toStaticIpConfiguration() {
-        return new StaticIpConfiguration.Builder()
-                .setIpAddress(ipAddress)
-                .setGateway(gateway)
-                .setDnsServers(dnsServers)
-                .setDomains(domains)
-                .build();
-    }
-
-    public DhcpResults(StaticIpConfiguration source) {
-        if (source != null) {
-            ipAddress = source.getIpAddress();
-            gateway = source.getGateway();
-            dnsServers.addAll(source.getDnsServers());
-            domains = source.getDomains();
-        }
-    }
-
-    /** copy constructor */
-    public DhcpResults(DhcpResults source) {
-        this(source == null ? null : source.toStaticIpConfiguration());
-        if (source != null) {
-            serverAddress = source.serverAddress;
-            vendorInfo = source.vendorInfo;
-            leaseDuration = source.leaseDuration;
-            mtu = source.mtu;
-            serverHostName = source.serverHostName;
-            captivePortalApiUrl = source.captivePortalApiUrl;
-        }
-    }
-
-    /**
-     * @see StaticIpConfiguration#getRoutes(String)
-     * @hide
-     */
-    public List<RouteInfo> getRoutes(String iface) {
-        return toStaticIpConfiguration().getRoutes(iface);
-    }
-
-    /**
-     * Test if this DHCP lease includes vendor hint that network link is
-     * metered, and sensitive to heavy data transfers.
-     */
-    public boolean hasMeteredHint() {
-        if (vendorInfo != null) {
-            return vendorInfo.contains("ANDROID_METERED");
-        } else {
-            return false;
-        }
-    }
-
-    public void clear() {
-        ipAddress = null;
-        gateway = null;
-        dnsServers.clear();
-        domains = null;
-        serverAddress = null;
-        vendorInfo = null;
-        leaseDuration = 0;
-        mtu = 0;
-        serverHostName = null;
-        captivePortalApiUrl = null;
-    }
-
-    @Override
-    public String toString() {
-        StringBuffer str = new StringBuffer(super.toString());
-
-        str.append(" DHCP server ").append(serverAddress);
-        str.append(" Vendor info ").append(vendorInfo);
-        str.append(" lease ").append(leaseDuration).append(" seconds");
-        if (mtu != 0) str.append(" MTU ").append(mtu);
-        str.append(" Servername ").append(serverHostName);
-        if (captivePortalApiUrl != null) {
-            str.append(" CaptivePortalApiUrl ").append(captivePortalApiUrl);
-        }
-
-        return str.toString();
-    }
-
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (this == obj) return true;
-
-        if (!(obj instanceof DhcpResults)) return false;
-
-        DhcpResults target = (DhcpResults)obj;
-
-        return toStaticIpConfiguration().equals(target.toStaticIpConfiguration())
-                && Objects.equals(serverAddress, target.serverAddress)
-                && Objects.equals(vendorInfo, target.vendorInfo)
-                && Objects.equals(serverHostName, target.serverHostName)
-                && leaseDuration == target.leaseDuration
-                && mtu == target.mtu
-                && Objects.equals(captivePortalApiUrl, target.captivePortalApiUrl);
-    }
-
-    /**
-     * Implement the Parcelable interface
-     */
-    public static final @android.annotation.NonNull Creator<DhcpResults> CREATOR =
-        new Creator<DhcpResults>() {
-            public DhcpResults createFromParcel(Parcel in) {
-                return readFromParcel(in);
-            }
-
-            public DhcpResults[] newArray(int size) {
-                return new DhcpResults[size];
-            }
-        };
-
-    /** Implement the Parcelable interface */
-    public void writeToParcel(Parcel dest, int flags) {
-        toStaticIpConfiguration().writeToParcel(dest, flags);
-        dest.writeInt(leaseDuration);
-        dest.writeInt(mtu);
-        InetAddressUtils.parcelInetAddress(dest, serverAddress, flags);
-        dest.writeString(vendorInfo);
-        dest.writeString(serverHostName);
-        dest.writeString(captivePortalApiUrl);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    private static DhcpResults readFromParcel(Parcel in) {
-        final StaticIpConfiguration s = StaticIpConfiguration.CREATOR.createFromParcel(in);
-        final DhcpResults dhcpResults = new DhcpResults(s);
-        dhcpResults.leaseDuration = in.readInt();
-        dhcpResults.mtu = in.readInt();
-        dhcpResults.serverAddress = (Inet4Address) InetAddressUtils.unparcelInetAddress(in);
-        dhcpResults.vendorInfo = in.readString();
-        dhcpResults.serverHostName = in.readString();
-        dhcpResults.captivePortalApiUrl = in.readString();
-        return dhcpResults;
-    }
-
-    // Utils for jni population - false on success
-    // Not part of the superclass because they're only used by the JNI iterface to the DHCP daemon.
-    public boolean setIpAddress(String addrString, int prefixLength) {
-        try {
-            Inet4Address addr = (Inet4Address) InetAddresses.parseNumericAddress(addrString);
-            ipAddress = new LinkAddress(addr, prefixLength);
-        } catch (IllegalArgumentException|ClassCastException e) {
-            Log.e(TAG, "setIpAddress failed with addrString " + addrString + "/" + prefixLength);
-            return true;
-        }
-        return false;
-    }
-
-    public boolean setGateway(String addrString) {
-        try {
-            gateway = InetAddresses.parseNumericAddress(addrString);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "setGateway failed with addrString " + addrString);
-            return true;
-        }
-        return false;
-    }
-
-    public boolean addDns(String addrString) {
-        if (TextUtils.isEmpty(addrString) == false) {
-            try {
-                dnsServers.add(InetAddresses.parseNumericAddress(addrString));
-            } catch (IllegalArgumentException e) {
-                Log.e(TAG, "addDns failed with addrString " + addrString);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public LinkAddress getIpAddress() {
-        return ipAddress;
-    }
-
-    public void setIpAddress(LinkAddress ipAddress) {
-        this.ipAddress = ipAddress;
-    }
-
-    public InetAddress getGateway() {
-        return gateway;
-    }
-
-    public void setGateway(InetAddress gateway) {
-        this.gateway = gateway;
-    }
-
-    public List<InetAddress> getDnsServers() {
-        return dnsServers;
-    }
-
-    /**
-     * Add a DNS server to this configuration.
-     */
-    public void addDnsServer(InetAddress server) {
-        dnsServers.add(server);
-    }
-
-    public String getDomains() {
-        return domains;
-    }
-
-    public void setDomains(String domains) {
-        this.domains = domains;
-    }
-
-    public Inet4Address getServerAddress() {
-        return serverAddress;
-    }
-
-    public void setServerAddress(Inet4Address addr) {
-        serverAddress = addr;
-    }
-
-    public int getLeaseDuration() {
-        return leaseDuration;
-    }
-
-    public void setLeaseDuration(int duration) {
-        leaseDuration = duration;
-    }
-
-    public String getVendorInfo() {
-        return vendorInfo;
-    }
-
-    public void setVendorInfo(String info) {
-        vendorInfo = info;
-    }
-
-    public int getMtu() {
-        return mtu;
-    }
-
-    public void setMtu(int mtu) {
-        this.mtu = mtu;
-    }
-
-    public String getCaptivePortalApiUrl() {
-        return captivePortalApiUrl;
-    }
-
-    public void setCaptivePortalApiUrl(String url) {
-        captivePortalApiUrl = url;
-    }
-}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 6284f56..dc24106 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -72,9 +72,9 @@
     SubscriptionPlan getSubscriptionPlan(in NetworkTemplate template);
     void notifyStatsProviderWarningOrLimitReached();
     SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
-    void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
+    void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, long expirationDurationMillis, String callingPackage);
     String getSubscriptionPlansOwner(int subId);
-    void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes, long timeoutMillis, String callingPackage);
+    void setSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes, long expirationDurationMillis, String callingPackage);
 
     void factoryReset(String subscriber);
 
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 596f431..714227d 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -338,7 +338,9 @@
         out.writeInt(TEMPLATE_BACKUP_VERSION_LATEST);
 
         out.writeInt(template.getMatchRule());
-        BackupUtils.writeString(out, template.getSubscriberIds().iterator().next());
+        final Set<String> subscriberIds = template.getSubscriberIds();
+        BackupUtils.writeString(out, subscriberIds.isEmpty()
+                ? null : subscriberIds.iterator().next());
         BackupUtils.writeString(out, template.getWifiNetworkKeys().isEmpty()
                 ? null : template.getWifiNetworkKeys().iterator().next());
         out.writeInt(template.getMeteredness());
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 9122adf..d8f098e 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -482,8 +482,8 @@
      * @param networkTypes the network types this override applies to. If no
      *            network types are specified, override values will be ignored.
      *            {@see TelephonyManager#getAllNetworkTypes()}
-     * @param timeoutMillis the timeout after which the requested override will
-     *            be automatically cleared, or {@code 0} to leave in the
+     * @param expirationDurationMillis the duration after which the requested override
+     *            will be automatically cleared, or {@code 0} to leave in the
      *            requested state until explicitly cleared, or the next reboot,
      *            whichever happens first
      * @param callingPackage the name of the package making the call.
@@ -491,11 +491,11 @@
      */
     public void setSubscriptionOverride(int subId, @SubscriptionOverrideMask int overrideMask,
             @SubscriptionOverrideMask int overrideValue,
-            @NonNull @Annotation.NetworkType int[] networkTypes, long timeoutMillis,
+            @NonNull @Annotation.NetworkType int[] networkTypes, long expirationDurationMillis,
             @NonNull String callingPackage) {
         try {
             mService.setSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes,
-                    timeoutMillis, callingPackage);
+                    expirationDurationMillis, callingPackage);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -506,13 +506,16 @@
      *
      * @param subId the subscriber this relationship applies to.
      * @param plans the list of plans.
+     * @param expirationDurationMillis the duration after which the subscription plans
+     *            will be automatically cleared, or {@code 0} to leave the plans until
+     *            explicitly cleared, or the next reboot, whichever happens first
      * @param callingPackage the name of the package making the call
      * @hide
      */
     public void setSubscriptionPlans(int subId, @NonNull SubscriptionPlan[] plans,
-            @NonNull String callingPackage) {
+            long expirationDurationMillis, @NonNull String callingPackage) {
         try {
-            mService.setSubscriptionPlans(subId, plans, callingPackage);
+            mService.setSubscriptionPlans(subId, plans, expirationDurationMillis, callingPackage);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index f16bbc6..071bdea 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -24,8 +24,6 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
 import android.content.Context;
 import android.net.NetworkStack;
 import android.os.connectivity.CellularBatteryStats;
@@ -523,8 +521,6 @@
      * @param reason why Bluetooth has been turned on
      * @param packageName package responsible for this change
      */
-    @RequiresLegacyBluetoothAdminPermission
-    @RequiresBluetoothConnectPermission
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
     public void reportBluetoothOn(int uid, int reason, @NonNull String packageName) {
         try {
@@ -541,8 +537,6 @@
      * @param reason why Bluetooth has been turned on
      * @param packageName package responsible for this change
      */
-    @RequiresLegacyBluetoothAdminPermission
-    @RequiresBluetoothConnectPermission
     @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
     public void reportBluetoothOff(int uid, int reason, @NonNull String packageName) {
         try {
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index d9c9a2b..bc7fb78 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -63,7 +63,7 @@
     boolean isUserTypeEnabled(in String userType);
     boolean canAddMoreUsersOfType(in String userType);
     int getRemainingCreatableUserCount(in String userType);
-    int getRemainingCreatableProfileCount(in String userType, int userId, boolean allowedToRemoveOne);
+    int getRemainingCreatableProfileCount(in String userType, int userId);
     boolean canAddMoreProfilesToUser(in String userType, int userId, boolean allowedToRemoveOne);
     boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne);
     UserInfo getProfileParent(int userId);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7b8d34b..2bd1dbb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4055,9 +4055,6 @@
      * <p>Note that is applicable to any profile type (currently not including Restricted profiles).
      *
      * @param userType the type of profile, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}.
-     * @param allowedToRemoveOne whether removing an existing profile of given type -if there is-
-     *                           from the context user to make up space should be taken into account
-     *                           for the calculation.
      * @return how many additional profiles can be created.
      * @hide
      */
@@ -4068,13 +4065,11 @@
             android.Manifest.permission.QUERY_USERS
     })
     @UserHandleAware
-    public int getRemainingCreatableProfileCount(@NonNull String userType,
-            boolean allowedToRemoveOne) {
+    public int getRemainingCreatableProfileCount(@NonNull String userType) {
         Objects.requireNonNull(userType, "userType must not be null");
         try {
             // TODO(b/142482943): Perhaps let the following code apply to restricted users too.
-            return mService.getRemainingCreatableProfileCount(userType, mUserId,
-                    allowedToRemoveOne);
+            return mService.getRemainingCreatableProfileCount(userType, mUserId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 1c0320e..619c870 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -79,7 +79,8 @@
     void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
 
     void startOneTimePermissionSession(String packageName, int userId, long timeout,
-            int importanceToResetTimer, int importanceToKeepSessionAlive);
+            long revokeAfterKilledDelay, int importanceToResetTimer,
+            int importanceToKeepSessionAlive);
 
     void stopOneTimePermissionSession(String packageName, int userId);
 
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 0cf06aa..a005ab4e 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -907,21 +907,23 @@
      * <li>Each permission in {@code permissions} must be a runtime permission.
      * </ul>
      * <p>
-     * For every permission in {@code permissions}, the entire permission group it belongs to will
-     * be revoked. This revocation happens asynchronously and kills all processes running in the
-     * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+     * Background permissions which have no corresponding foreground permission still granted once
+     * the revocation is effective will also be revoked.
+     * <p>
+     * This revocation happens asynchronously and kills all processes running in the same UID as
+     * {@code packageName}. It will be triggered once it is safe to do so.
      *
      * @param packageName The name of the package for which the permissions will be revoked.
      * @param permissions List of permissions to be revoked.
-     * @param callback Callback called when the revocation request has been completed.
      *
-     * @see Context#revokeOwnPermissionsOnKill(Collection)
+     * @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
      *
      * @hide
      */
     public void revokeOwnPermissionsOnKill(@NonNull String packageName,
-            @NonNull List<String> permissions, AndroidFuture<Void> callback) {
+            @NonNull List<String> permissions) {
         mRemoteService.postAsync(service -> {
+            AndroidFuture<Void> callback = new AndroidFuture<>();
             service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
             return callback;
         }).whenComplete((result, err) -> {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 8d9f82b..3292e71 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -291,7 +291,7 @@
 
     /**
      * Called when a package is considered inactive based on the criteria given by
-     * {@link PermissionManager#startOneTimePermissionSession(String, long, int, int)}.
+     * {@link PermissionManager#startOneTimePermissionSession(String, long, long, int, int)}.
      * This method is called at the end of a one-time permission session
      *
      * @param packageName The package that has been inactive
@@ -329,9 +329,11 @@
      * Triggers the revocation of one or more permissions for a package. This should only be called
      * at the request of {@code packageName}.
      * <p>
-     * For every permission in {@code permissions}, the entire permission group it belongs to will
-     * be revoked. This revocation happens asynchronously and kills all processes running in the
-     * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+     * Background permissions which have no corresponding foreground permission still granted once
+     * the revocation is effective will also be revoked.
+     * <p>
+     * This revocation happens asynchronously and kills all processes running in the same UID as
+     * {@code packageName}. It will be triggered once it is safe to do so.
      *
      * @param packageName The name of the package for which the permissions will be revoked.
      * @param permissions List of permissions to be revoked.
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 15f13eb..12fa0dd 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -20,6 +20,7 @@
 
 import android.Manifest;
 import android.annotation.CheckResult;
+import android.annotation.DurationMillisLong;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -1282,6 +1283,22 @@
     }
 
     /**
+     * Starts a one-time permission session for a given package.
+     * @see #startOneTimePermissionSession(String, long, long, int, int)
+     * @hide
+     * @deprecated Use {@link #startOneTimePermissionSession(String, long, long, int, int)} instead
+     */
+    @Deprecated
+    @SystemApi
+    @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
+    public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
+            @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
+            @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
+        startOneTimePermissionSession(packageName, timeoutMillis, -1,
+                importanceToResetTimer, importanceToKeepSessionAlive);
+    }
+
+    /**
      * Starts a one-time permission session for a given package. A one-time permission session is
      * ended if app becomes inactive. Inactivity is defined as the package's uid importance level
      * staying > importanceToResetTimer for timeoutMillis milliseconds. If the package's uid
@@ -1301,25 +1318,33 @@
      * {@link PermissionControllerService#onOneTimePermissionSessionTimeout(String)} is invoked.
      * </p>
      * <p>
-     * Note that if there is currently an active session for a package a new one isn't created and
-     * the existing one isn't changed.
+     * Note that if there is currently an active session for a package a new one isn't created but
+     * each parameter of the existing one will be updated to the more aggressive of both sessions.
+     * This means that durations will be set to the shortest parameter and importances will be set
+     * to the lowest one.
      * </p>
      * @param packageName The package to start a one-time permission session for
      * @param timeoutMillis Number of milliseconds for an app to be in an inactive state
+     * @param revokeAfterKilledDelayMillis Number of milliseconds to wait before revoking on the
+     *                                     event an app is terminated. Set to -1 to use default
+     *                                     value for the device.
      * @param importanceToResetTimer The least important level to uid must be to reset the timer
      * @param importanceToKeepSessionAlive The least important level the uid must be to keep the
-     *                                    session alive
+     *                                     session alive
      *
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
-    public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
+    public void startOneTimePermissionSession(@NonNull String packageName,
+            @DurationMillisLong long timeoutMillis,
+            @DurationMillisLong long revokeAfterKilledDelayMillis,
             @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
             @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
         try {
             mPermissionManager.startOneTimePermissionSession(packageName, mContext.getUserId(),
-                    timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
+                    timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer,
+                    importanceToKeepSessionAlive);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ee6f9c0..3f41458 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6094,11 +6094,9 @@
         }
 
         /** @hide */
-        @SystemApi
-        @Nullable
-        @SuppressLint("VisiblySynchronized")
-        public static String getStringForUser(@NonNull ContentResolver resolver,
-                @NonNull String name, int userHandle) {
+        @UnsupportedAppUsage
+        public static String getStringForUser(ContentResolver resolver, String name,
+                int userHandle) {
             if (MOVED_TO_GLOBAL.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
                         + " to android.provider.Settings.Global.");
@@ -6330,9 +6328,8 @@
         }
 
         /** @hide */
-        @SystemApi
-        public static int getIntForUser(@NonNull ContentResolver cr, @NonNull String name,
-                int def, int userHandle) {
+        @UnsupportedAppUsage
+        public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
             String v = getStringForUser(cr, name, userHandle);
             return parseIntSettingWithDefault(v, def);
         }
@@ -16819,6 +16816,16 @@
                 "low_power_standby_active_during_maintenance";
 
         /**
+         * Timeout for the system server watchdog.
+         *
+         * @see {@link com.android.server.Watchdog}.
+         *
+         * @hide
+         */
+        public static final String WATCHDOG_TIMEOUT_MILLIS =
+                "system_server_watchdog_timeout_ms";
+
+        /**
          * Settings migrated from Wear OS settings provider.
          * @hide
          */
@@ -17325,6 +17332,12 @@
                     "clockwork_long_press_to_assistant_enabled";
 
             /*
+             * Whether the device has Cooldown Mode enabled.
+             * @hide
+             */
+            public static final String COOLDOWN_MODE_ON = "cooldown_mode_on";
+
+            /*
              * Whether the device has Wet Mode/ Touch Lock Mode enabled.
              * @hide
              */
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 34e35d4..3ff0161 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1425,25 +1425,6 @@
         public static final String KEY_TYPE = "key_type";
 
         /**
-         * MVNO type:
-         * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
-         * <P> Type: TEXT </P>
-         */
-        public static final String MVNO_TYPE = "mvno_type";
-
-        /**
-         * MVNO data.
-         * Use the following examples.
-         * <ul>
-         *     <li>SPN: A MOBILE, BEN NL, ...</li>
-         *     <li>IMSI: 302720x94, 2060188, ...</li>
-         *     <li>GID: 4E, 33, ...</li>
-         * </ul>
-         * <P> Type: TEXT </P>
-         */
-        public static final String MVNO_MATCH_DATA = "mvno_match_data";
-
-        /**
          * The carrier public key that is used for the IMSI encryption.
          * <P> Type: TEXT </P>
          */
@@ -1470,6 +1451,11 @@
         public static final String LAST_MODIFIED = "last_modified";
 
         /**
+         * Carrier ID of the operetor.
+         * <P> Type: TEXT </P>
+         */
+        public static final String CARRIER_ID = "carrier_id";
+        /**
          * The {@code content://} style URL for this table.
          */
         @NonNull
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index fde8bfe..bb1f393 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -31,12 +31,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
@@ -45,11 +39,9 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.util.AttributeSet;
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Slog;
-import android.util.Xml;
 import android.view.ActionMode;
 import android.view.Display;
 import android.view.KeyEvent;
@@ -65,14 +57,9 @@
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.android.internal.R;
 import com.android.internal.util.DumpUtils;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.FileDescriptor;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
 import java.util.function.Consumer;
@@ -172,9 +159,8 @@
  * </pre>
  */
 public class DreamService extends Service implements Window.Callback {
-    private static final String TAG = DreamService.class.getSimpleName();
-    private final String mTag = TAG + "[" + getClass().getSimpleName() + "]";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private final String mTag =
+            DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
 
     /**
      * The name of the dream manager service.
@@ -205,11 +191,6 @@
     public static final String DREAM_META_DATA = "android.service.dream";
 
     /**
-     * Name of the root tag under which a Dream defines its metadata in an XML file.
-     */
-    private static final String DREAM_META_DATA_ROOT_TAG = "dream";
-
-    /**
      * Extra containing a boolean for whether to show complications on the overlay.
      * @hide
      */
@@ -258,16 +239,13 @@
             mRequests = new ArrayDeque<>();
         }
 
-        public void bind(Context context, @Nullable ComponentName overlayService,
-                ComponentName dreamService) {
+        public void bind(Context context, @Nullable ComponentName overlayService) {
             if (overlayService == null) {
                 return;
             }
 
             final Intent overlayIntent = new Intent();
             overlayIntent.setComponent(overlayService);
-            overlayIntent.putExtra(EXTRA_SHOW_COMPLICATIONS,
-                    fetchShouldShowComplications(context, dreamService));
 
             context.bindService(overlayIntent,
                     this, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE);
@@ -989,8 +967,7 @@
 
         // Connect to the overlay service if present.
         if (!mWindowless) {
-            mOverlayConnection.bind(this, intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT),
-                    new ComponentName(this, getClass()));
+            mOverlayConnection.bind(this, intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT));
         }
 
         return mDreamServiceWrapper;
@@ -1104,84 +1081,6 @@
     // end public api
 
     /**
-     * Parses and returns metadata of the dream service indicated by the service info. Returns null
-     * if metadata cannot be found.
-     *
-     * Note that {@link ServiceInfo} must be fetched with {@link PackageManager#GET_META_DATA} flag.
-     *
-     * @hide
-     */
-    @Nullable
-    public static DreamMetadata getDreamMetadata(Context context, ServiceInfo serviceInfo) {
-        final PackageManager pm = context.getPackageManager();
-
-        final TypedArray rawMetadata = readMetadata(pm, serviceInfo);
-        if (rawMetadata == null) return null;
-
-        final DreamMetadata metadata = new DreamMetadata(
-                convertToComponentName(rawMetadata.getString(
-                        com.android.internal.R.styleable.Dream_settingsActivity), serviceInfo),
-                rawMetadata.getDrawable(
-                        com.android.internal.R.styleable.Dream_previewImage),
-                rawMetadata.getBoolean(R.styleable.Dream_showClockAndComplications,
-                        DEFAULT_SHOW_COMPLICATIONS));
-        rawMetadata.recycle();
-        return metadata;
-    }
-
-    /**
-     * Returns the raw XML metadata fetched from the ${@link ServiceInfo}.
-     *
-     * Returns <code>null</code> if the ${@link ServiceInfo} doesn't contain valid dream metadata.
-     */
-    @Nullable
-    private static TypedArray readMetadata(PackageManager pm, ServiceInfo serviceInfo) {
-        if (serviceInfo == null || serviceInfo.metaData == null) {
-            return null;
-        }
-
-        try (XmlResourceParser parser =
-                     serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA)) {
-            if (parser == null) {
-                if (DEBUG) Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " metadata");
-                return null;
-            }
-
-            final Resources res = pm.getResourcesForApplication(serviceInfo.applicationInfo);
-            final AttributeSet attrs = Xml.asAttributeSet(parser);
-            while (true) {
-                final int type = parser.next();
-                if (type == XmlPullParser.END_DOCUMENT || type == XmlPullParser.START_TAG) {
-                    break;
-                }
-            }
-
-            if (!parser.getName().equals(DREAM_META_DATA_ROOT_TAG)) {
-                if (DEBUG) {
-                    Log.w(TAG, "Metadata does not start with " + DREAM_META_DATA_ROOT_TAG + " tag");
-                }
-                return null;
-            }
-
-            return res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream);
-        } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
-            if (DEBUG) Log.e(TAG, "Error parsing: " + serviceInfo.packageName, e);
-            return null;
-        }
-    }
-
-    private static ComponentName convertToComponentName(String flattenedString,
-            ServiceInfo serviceInfo) {
-        if (flattenedString == null) return null;
-
-        if (!flattenedString.contains("/")) {
-            return new ComponentName(serviceInfo.packageName, flattenedString);
-        }
-
-        return ComponentName.unflattenFromString(flattenedString);
-    }
-
-    /**
      * Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
      *
      * Must run on mHandler.
@@ -1343,30 +1242,6 @@
         return (oldFlags&~mask) | (flags&mask);
     }
 
-    /**
-     * Fetches metadata of the dream indicated by the ${@link ComponentName}, and returns whether
-     * the dream should show complications on the overlay. If not defined, returns
-     * ${@link DreamService#DEFAULT_SHOW_COMPLICATIONS}.
-     */
-    private static boolean fetchShouldShowComplications(Context context,
-            ComponentName componentName) {
-        final PackageManager pm = context.getPackageManager();
-
-        try {
-            final ServiceInfo si = pm.getServiceInfo(componentName,
-                    PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
-            final DreamMetadata metadata = getDreamMetadata(context, si);
-
-            if (metadata != null) {
-                return metadata.showComplications;
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            if (DEBUG) Log.w(TAG, "cannot find component " + componentName.flattenToShortString());
-        }
-
-        return DEFAULT_SHOW_COMPLICATIONS;
-    }
-
     @Override
     protected void dump(final FileDescriptor fd, PrintWriter pw, final String[] args) {
         DumpUtils.dumpAsync(mHandler, (pw1, prefix) -> dumpOnHandler(fd, pw1, args), pw, "", 1000);
@@ -1427,27 +1302,4 @@
             onWindowCreated(a.getWindow());
         }
     }
-
-    /**
-     * Represents metadata defined in {@link android.R.styleable#Dream &lt;dream&gt;}.
-     *
-     * @hide
-     */
-    public static final class DreamMetadata {
-        @Nullable
-        public final ComponentName settingsActivity;
-
-        @Nullable
-        public final Drawable previewImage;
-
-        @Nullable
-        public final boolean showComplications;
-
-        DreamMetadata(ComponentName settingsActivity, Drawable previewImage,
-                boolean showComplications) {
-            this.settingsActivity = settingsActivity;
-            this.previewImage = previewImage;
-            this.showComplications = showComplications;
-        }
-    }
 }
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index e33f180..468e087c 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -20,15 +20,23 @@
 import android.annotation.IntDef;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.app.ActivityTaskManager;
+import android.app.Instrumentation;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.view.SurfaceControlViewHost;
 import android.view.View;
@@ -41,6 +49,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -120,6 +129,7 @@
     private LifecycleState mLifecycleState = LifecycleState.INITIALIZED;
     private boolean mAreTransientInsetsVisibleDueToGesture = false;
     private IGameSessionController mGameSessionController;
+    private Context mContext;
     private int mTaskId;
     private GameSessionRootView mGameSessionRootView;
     private SurfaceControlViewHost mSurfaceControlViewHost;
@@ -137,6 +147,7 @@
             int heightPx) {
         mGameSessionController = gameSessionController;
         mTaskId = taskId;
+        mContext = context;
         mSurfaceControlViewHost = surfaceControlViewHost;
         mGameSessionRootView = new GameSessionRootView(context, mSurfaceControlViewHost);
         surfaceControlViewHost.setView(mGameSessionRootView, widthPx, heightPx);
@@ -299,6 +310,8 @@
      * {@code View} may not be cleared once set, but may be replaced by invoking
      * {@link #setTaskOverlayView(View, ViewGroup.LayoutParams)} again.
      *
+     * <p><b>WARNING</b>: Callers <b>must</b> ensure that only trusted views are provided.
+     *
      * @param view         The desired content to display.
      * @param layoutParams Layout parameters for the view.
      */
@@ -456,4 +469,67 @@
                 break;
         }
     }
+
+    /**
+     * Launches an activity within the same activity stack as the {@link GameSession}. When the
+     * target activity exits, {@link GameSessionActivityCallback#onActivityResult(int, Intent)} will
+     * be invoked with the result code and result data directly from the target activity (in other
+     * words, the result code and data set via the target activity's
+     * {@link android.app.Activity#startActivityForResult} call). The caller is expected to handle
+     * the results that the target activity returns.
+     *
+     * <p>Any activity that an app would normally be able to start via {@link
+     * android.app.Activity#startActivityForResult} will be startable via this method.
+     *
+     * <p>Started activities may see a different calling package than the game session's package
+     * when calling {@link android.app.Activity#getCallingPackage()}.
+     *
+     * <p> If an exception is thrown while handling {@code intent},
+     * {@link GameSessionActivityCallback#onActivityStartFailed(Throwable)} will be called instead
+     * of {@link GameSessionActivityCallback#onActivityResult(int, Intent)}.
+     *
+     * @param intent   The intent to start.
+     * @param options  Additional options for how the Activity should be started. See
+     *                 {@link android.app.Activity#startActivityForResult(Intent, int, Bundle)} for
+     *                 more details. This value may be null.
+     * @param executor Executor on which {@code callback} should be invoked.
+     * @param callback Callback to be invoked once the started activity has finished.
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)
+    public final void startActivityFromGameSessionForResult(
+            @NonNull Intent intent, @Nullable Bundle options, @NonNull Executor executor,
+            @NonNull GameSessionActivityCallback callback) {
+        Objects.requireNonNull(intent);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+
+        AndroidFuture<GameSessionActivityResult> future =
+                new AndroidFuture<GameSessionActivityResult>()
+                        .whenCompleteAsync((result, ex) -> {
+                            if (ex != null) {
+                                callback.onActivityStartFailed(ex);
+                                return;
+                            }
+                            callback.onActivityResult(result.getResultCode(), result.getData());
+                        }, executor);
+
+        final Intent trampolineIntent = new Intent();
+        trampolineIntent.setComponent(
+                new ComponentName(
+                        "android", "android.service.games.GameSessionTrampolineActivity"));
+        trampolineIntent.putExtra(GameSessionTrampolineActivity.INTENT_KEY, intent);
+        trampolineIntent.putExtra(GameSessionTrampolineActivity.OPTIONS_KEY, options);
+        trampolineIntent.putExtra(
+                GameSessionTrampolineActivity.FUTURE_KEY, future);
+
+        try {
+            int result = ActivityTaskManager.getService().startActivityFromGameSession(
+                    mContext.getIApplicationThread(), mContext.getPackageName(), "GameSession",
+                    Binder.getCallingPid(), Binder.getCallingUid(), trampolineIntent, mTaskId,
+                    UserHandle.myUserId());
+            Instrumentation.checkStartActivityResult(result, trampolineIntent);
+        } catch (Throwable t) {
+            executor.execute(() -> callback.onActivityStartFailed(t));
+        }
+    }
 }
diff --git a/core/java/android/service/games/GameSessionActivityCallback.java b/core/java/android/service/games/GameSessionActivityCallback.java
new file mode 100644
index 0000000..3b11df1
--- /dev/null
+++ b/core/java/android/service/games/GameSessionActivityCallback.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Intent;
+import android.os.Bundle;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Callback invoked when an activity launched via
+ * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+ * GameSessionActivityCallback)}} has returned a result or failed to start.
+ *
+ * @hide
+ */
+@SystemApi
+public interface GameSessionActivityCallback {
+    /**
+     * Callback invoked when an activity launched via
+     * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+     * GameSessionActivityCallback)}} has returned a result.
+     *
+     * @param resultCode The result code of the launched activity. See {@link
+     *                   android.app.Activity#setResult(int)}.
+     * @param data       Any data returned by the launched activity. See {@link
+     *                   android.app.Activity#setResult(int, Intent)}.
+     */
+    void onActivityResult(int resultCode, @Nullable Intent data);
+
+    /**
+     * Callback invoked when a throwable was thrown when launching the {@link Intent} in
+     * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+     * GameSessionActivityCallback)}}.
+     */
+    default void onActivityStartFailed(@NonNull Throwable t) {}
+}
diff --git a/core/java/android/service/games/GameSessionActivityResult.java b/core/java/android/service/games/GameSessionActivityResult.java
new file mode 100644
index 0000000..a2ec6ad
--- /dev/null
+++ b/core/java/android/service/games/GameSessionActivityResult.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+final class GameSessionActivityResult implements Parcelable {
+
+    public static final Creator<GameSessionActivityResult> CREATOR =
+            new Creator<GameSessionActivityResult>() {
+                @Override
+                public GameSessionActivityResult createFromParcel(Parcel in) {
+                    int resultCode = in.readInt();
+                    Intent data = in.readParcelable(Intent.class.getClassLoader(), Intent.class);
+                    return new GameSessionActivityResult(resultCode, data);
+                }
+
+                @Override
+                public GameSessionActivityResult[] newArray(int size) {
+                    return new GameSessionActivityResult[size];
+                }
+            };
+
+    private final int mResultCode;
+    @Nullable
+    private final Intent mData;
+
+    GameSessionActivityResult(int resultCode, @Nullable Intent data) {
+        mResultCode = resultCode;
+        mData = data;
+    }
+
+    int getResultCode() {
+        return mResultCode;
+    }
+
+    @Nullable
+    Intent getData() {
+        return mData;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mResultCode);
+        dest.writeParcelable(mData, flags);
+    }
+}
diff --git a/core/java/android/service/games/GameSessionTrampolineActivity.java b/core/java/android/service/games/GameSessionTrampolineActivity.java
new file mode 100644
index 0000000..ddea098
--- /dev/null
+++ b/core/java/android/service/games/GameSessionTrampolineActivity.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.games;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Trampoline activity that enables the
+ * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+ * GameSessionActivityCallback)} API by reusing existing activity result infrastructure in the
+ * {@link Activity} class. This activity forwards activity results back to the calling
+ * {@link GameSession} via {@link AndroidFuture}.
+ *
+ * @hide
+ */
+public final class GameSessionTrampolineActivity extends Activity {
+    private static final String TAG = "GameSessionTrampoline";
+    private static final int REQUEST_CODE = 1;
+
+    static final String FUTURE_KEY = "GameSessionTrampolineActivity.future";
+    static final String INTENT_KEY = "GameSessionTrampolineActivity.intent";
+    static final String OPTIONS_KEY = "GameSessionTrampolineActivity.options";
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        try {
+            startActivityAsCaller(
+                    getIntent().getParcelableExtra(INTENT_KEY),
+                    getIntent().getBundleExtra(OPTIONS_KEY),
+                    null,
+                    false,
+                    getUserId(),
+                    REQUEST_CODE);
+        } catch (Exception e) {
+            Slog.w(TAG, "Unable to launch activity from game session");
+            AndroidFuture<GameSessionActivityResult> future = getIntent().getParcelableExtra(
+                    FUTURE_KEY);
+            future.completeExceptionally(e);
+            finish();
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode != REQUEST_CODE) {
+            // Something went very wrong if we hit this code path, and we should bail.
+            throw new IllegalStateException("Unexpected request code: " + requestCode);
+        }
+
+        AndroidFuture<GameSessionActivityResult> future = getIntent().getParcelableExtra(
+                FUTURE_KEY);
+        future.complete(new GameSessionActivityResult(resultCode, data));
+        finish();
+    }
+}
diff --git a/core/java/android/service/games/IGameSessionController.aidl b/core/java/android/service/games/IGameSessionController.aidl
index 84311dc..fd99404 100644
--- a/core/java/android/service/games/IGameSessionController.aidl
+++ b/core/java/android/service/games/IGameSessionController.aidl
@@ -24,6 +24,6 @@
  */
 oneway interface IGameSessionController {
     void takeScreenshot(int taskId, in AndroidFuture gameScreenshotResultFuture);
-    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)")
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)")
     void restartGame(in int taskId);
 }
diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl
index 7c79b1a..986a41c 100644
--- a/core/java/android/speech/IRecognitionListener.aidl
+++ b/core/java/android/speech/IRecognitionListener.aidl
@@ -78,6 +78,24 @@
     void onPartialResults(in Bundle results);
 
     /**
+     * Called for each ready segment of a recognition request. To request segmented speech results
+     * use {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}. The callback might be called
+     * any number of times between {@link #onBeginningOfSpeech()} and
+     * {@link #onEndOfSegmentedSession()}.
+     *
+     * @param segmentResults the returned results. To retrieve the results in
+     *        ArrayList&lt;String&gt; format use {@link Bundle#getStringArrayList(String)} with
+     *        {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter
+    */
+    void onSegmentResults(in Bundle results);
+
+    /**
+     * Called at the end of a segmented recognition request. To request segmented speech results
+     * use {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}.
+     */
+    void onEndOfSegmentedSession();
+
+    /**
      * Reserved for adding future events.
      *
      * @param eventType the type of the occurred event
diff --git a/core/java/android/speech/RecognitionListener.java b/core/java/android/speech/RecognitionListener.java
index c94b60f..64fd09f 100644
--- a/core/java/android/speech/RecognitionListener.java
+++ b/core/java/android/speech/RecognitionListener.java
@@ -15,6 +15,7 @@
  */
 package android.speech;
 
+import android.annotation.NonNull;
 import android.content.Intent;
 import android.os.Bundle;
 
@@ -69,7 +70,13 @@
 
     /**
      * Called when recognition results are ready.
-     * 
+     *
+     * <p>
+     *     Called with the results for the full speech since {@link #onReadyForSpeech(Bundle)}.
+     *     To get recognition results in segments rather than for the full session see
+     *     {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}.
+     * </p>
+     *
      * @param results the recognition results. To retrieve the results in {@code
      *        ArrayList<String>} format use {@link Bundle#getStringArrayList(String)} with
      *        {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter. A float array of
@@ -92,6 +99,24 @@
     void onPartialResults(Bundle partialResults);
 
     /**
+     * Called for each ready segment of a recognition request. To request segmented speech results
+     * use {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}. The callback might be called
+     * any number of times between {@link #onReadyForSpeech(Bundle)} and
+     * {@link #onEndOfSegmentedSession()}.
+     *
+     * @param segmentResults the returned results. To retrieve the results in
+     *        ArrayList&lt;String&gt; format use {@link Bundle#getStringArrayList(String)} with
+     *        {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter
+     */
+    default void onSegmentResults(@NonNull Bundle segmentResults) {}
+
+    /**
+     * Called at the end of a segmented recognition request. To request segmented speech results
+     * use {@link RecognizerIntent#EXTRA_SEGMENT_SESSION}.
+     */
+    default void onEndOfSegmentedSession() {}
+
+    /**
      * Reserved for adding future events.
      * 
      * @param eventType the type of the occurred event
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index 5dbbc04..08136761 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -427,6 +427,26 @@
         }
 
         /**
+         * The service should call this method for each ready segment of a long recognition session.
+         *
+         * @param results the recognition results. To retrieve the results in {@code
+         *        ArrayList<String>} format use {@link Bundle#getStringArrayList(String)} with
+         *        {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter
+         */
+        @SuppressLint({"CallbackMethodName", "RethrowRemoteException"})
+        public void segmentResults(@NonNull Bundle results) throws RemoteException {
+            mListener.onSegmentResults(results);
+        }
+
+        /**
+         * The service should call this method to end a segmented session.
+         */
+        @SuppressLint({"CallbackMethodName", "RethrowRemoteException"})
+        public void endOfSegmentedSession() throws RemoteException {
+            mListener.onEndOfSegmentedSession();
+        }
+
+        /**
          * Return the Linux uid assigned to the process that sent you the current transaction that
          * is being processed. This is obtained from {@link Binder#getCallingUid()}.
          */
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 3183f15..271e307 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -426,4 +426,16 @@
      *
      */
     public static final String EXTRA_PREFER_OFFLINE = "android.speech.extra.PREFER_OFFLINE";
+
+    /**
+     * Optional boolean, when true and supported by the recognizer implementation it will split
+     * the recognition results in segments, returned via
+     * {@link RecognitionListener#onSegmentResults(Bundle)} and terminate the session with
+     * {@link RecognitionListener#onEndOfSegmentedSession()}. There will be no call to
+     * {@link RecognitionListener#onResults(Bundle)}. Callers can use
+     * {@link #EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS} and
+     * {@link #EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS} to tune how long the segments
+     * will be. Defaults to false.
+     */
+    public static final String EXTRA_SEGMENT_SESSION = "android.speech.extra.SEGMENT_SESSION";
 }
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 71c1e88..502558e 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -768,6 +768,8 @@
         private static final int MSG_PARTIAL_RESULTS = 7;
         private static final int MSG_RMS_CHANGED = 8;
         private static final int MSG_ON_EVENT = 9;
+        private static final int MSG_SEGMENT_RESULTS = 10;
+        private static final int MSG_SEGMENT_END_SESSION = 11;
 
         private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) {
             @Override
@@ -803,6 +805,12 @@
                     case MSG_ON_EVENT:
                         mInternalListener.onEvent(msg.arg1, (Bundle) msg.obj);
                         break;
+                    case MSG_SEGMENT_RESULTS:
+                        mInternalListener.onSegmentResults((Bundle) msg.obj);
+                        break;
+                    case MSG_SEGMENT_END_SESSION:
+                        mInternalListener.onEndOfSegmentedSession();
+                        break;
                 }
             }
         };
@@ -839,6 +847,14 @@
             Message.obtain(mInternalHandler, MSG_RMS_CHANGED, rmsdB).sendToTarget();
         }
 
+        public void onSegmentResults(final Bundle bundle) {
+            Message.obtain(mInternalHandler, MSG_SEGMENT_RESULTS, bundle).sendToTarget();
+        }
+
+        public void onEndOfSegmentedSession() {
+            Message.obtain(mInternalHandler, MSG_SEGMENT_END_SESSION).sendToTarget();
+        }
+
         public void onEvent(final int eventType, final Bundle params) {
             Message.obtain(mInternalHandler, MSG_ON_EVENT, eventType, eventType, params)
                     .sendToTarget();
diff --git a/core/java/android/util/Dumpable.java b/core/java/android/util/Dumpable.java
index 79c576d..955113d 100644
--- a/core/java/android/util/Dumpable.java
+++ b/core/java/android/util/Dumpable.java
@@ -35,8 +35,6 @@
         return getClass().getName();
     }
 
-    //TODO(b/149254050): decide whether it should take a ParcelFileDescription as well.
-
     /**
      * Dumps the internal state into the given {@code writer}.
      *
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
index 5425c21..c199b96 100644
--- a/core/java/android/util/OWNERS
+++ b/core/java/android/util/OWNERS
@@ -1,6 +1,5 @@
 per-file FeatureFlagUtils.java = sbasi@google.com
 per-file FeatureFlagUtils.java = tmfang@google.com
-per-file FeatureFlagUtils.java = asapperstein@google.com
 
 per-file AttributeSet.java = file:/core/java/android/content/res/OWNERS
 per-file TypedValue.java = file:/core/java/android/content/res/OWNERS
diff --git a/core/java/android/view/ActionProvider.java b/core/java/android/view/ActionProvider.java
index e1be0fe..1680fd2 100644
--- a/core/java/android/view/ActionProvider.java
+++ b/core/java/android/view/ActionProvider.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.util.Log;
@@ -67,7 +69,7 @@
      *
      * @param context Context for accessing resources.
      */
-    public ActionProvider(Context context) {
+    public ActionProvider(@NonNull Context context) {
     }
 
     /**
@@ -82,7 +84,7 @@
      * @deprecated use {@link #onCreateActionView(MenuItem)}
      */
     @Deprecated
-    public abstract View onCreateActionView();
+    public abstract @NonNull View onCreateActionView();
 
     /**
      * Factory method called by the Android framework to create new action views.
@@ -96,7 +98,7 @@
      * @param forItem MenuItem to create the action view for
      * @return the new action view
      */
-    public View onCreateActionView(MenuItem forItem) {
+    public @NonNull View onCreateActionView(@NonNull MenuItem forItem) {
         return onCreateActionView();
     }
 
@@ -200,7 +202,7 @@
      *
      * @param subMenu Submenu that will be displayed
      */
-    public void onPrepareSubMenu(SubMenu subMenu) {
+    public void onPrepareSubMenu(@NonNull SubMenu subMenu) {
     }
 
     /**
@@ -220,7 +222,7 @@
      * @hide Internal use only
      */
     @UnsupportedAppUsage
-    public void setSubUiVisibilityListener(SubUiVisibilityListener listener) {
+    public void setSubUiVisibilityListener(@Nullable SubUiVisibilityListener listener) {
         mSubUiVisibilityListener = listener;
     }
 
@@ -230,7 +232,7 @@
      *
      * @param listener listener to set
      */
-    public void setVisibilityListener(VisibilityListener listener) {
+    public void setVisibilityListener(@Nullable VisibilityListener listener) {
         if (mVisibilityListener != null) {
             Log.w(TAG, "setVisibilityListener: Setting a new ActionProvider.VisibilityListener " +
                     "when one is already set. Are you reusing this " + getClass().getSimpleName() +
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 9b36b9b..b3b7f10 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -260,7 +260,7 @@
         private final float mScale;
 
         public CutoutPathParserInfo(int displayWidth, int displayHeight, float density,
-                String cutoutSpec, @Rotation int rotation, float scale) {
+                @Nullable String cutoutSpec, @Rotation int rotation, float scale) {
             mDisplayWidth = displayWidth;
             mDisplayHeight = displayHeight;
             mDensity = density;
@@ -269,7 +269,7 @@
             mScale = scale;
         }
 
-        public CutoutPathParserInfo(CutoutPathParserInfo cutoutPathParserInfo) {
+        public CutoutPathParserInfo(@NonNull CutoutPathParserInfo cutoutPathParserInfo) {
             mDisplayWidth = cutoutPathParserInfo.mDisplayWidth;
             mDisplayHeight = cutoutPathParserInfo.mDisplayHeight;
             mDensity = cutoutPathParserInfo.mDensity;
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 63a8300..57ba7e9 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -23,6 +23,8 @@
 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP;
 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UiContext;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -68,7 +70,7 @@
          *
          * @param e The down motion event.
          */
-        boolean onDown(MotionEvent e);
+        boolean onDown(@NonNull MotionEvent e);
 
         /**
          * The user has performed a down {@link MotionEvent} and not performed
@@ -78,7 +80,7 @@
          *
          * @param e The down motion event
          */
-        void onShowPress(MotionEvent e);
+        void onShowPress(@NonNull MotionEvent e);
 
         /**
          * Notified when a tap occurs with the up {@link MotionEvent}
@@ -87,7 +89,7 @@
          * @param e The up motion event that completed the first tap
          * @return true if the event is consumed, else false
          */
-        boolean onSingleTapUp(MotionEvent e);
+        boolean onSingleTapUp(@NonNull MotionEvent e);
 
         /**
          * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the
@@ -104,7 +106,8 @@
          *              and {@code e2}.
          * @return true if the event is consumed, else false
          */
-        boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
+        boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float distanceX,
+                float distanceY);
 
         /**
          * Notified when a long press occurs with the initial on down {@link MotionEvent}
@@ -112,7 +115,7 @@
          *
          * @param e The initial on down motion event that started the longpress.
          */
-        void onLongPress(MotionEvent e);
+        void onLongPress(@NonNull MotionEvent e);
 
         /**
          * Notified of a fling event when it occurs with the initial on down {@link MotionEvent}
@@ -127,7 +130,8 @@
          *              along the y axis.
          * @return true if the event is consumed, else false
          */
-        boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
+        boolean onFling(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float velocityX,
+                float velocityY);
     }
 
     /**
@@ -146,7 +150,7 @@
          * @param e The down motion event of the single-tap.
          * @return true if the event is consumed, else false
          */
-        boolean onSingleTapConfirmed(MotionEvent e);
+        boolean onSingleTapConfirmed(@NonNull MotionEvent e);
  
         /**
          * Notified when a double-tap occurs. Triggered on the down event of second tap.
@@ -154,7 +158,7 @@
          * @param e The down motion event of the first tap of the double-tap.
          * @return true if the event is consumed, else false
          */
-        boolean onDoubleTap(MotionEvent e);
+        boolean onDoubleTap(@NonNull MotionEvent e);
 
         /**
          * Notified when an event within a double-tap gesture occurs, including
@@ -163,7 +167,7 @@
          * @param e The motion event that occurred during the double-tap gesture.
          * @return true if the event is consumed, else false
          */
-        boolean onDoubleTapEvent(MotionEvent e);
+        boolean onDoubleTapEvent(@NonNull MotionEvent e);
     }
 
     /**
@@ -178,7 +182,7 @@
          * @param e The motion event that occurred during the context click.
          * @return true if the event is consumed, else false
          */
-        boolean onContextClick(MotionEvent e);
+        boolean onContextClick(@NonNull MotionEvent e);
     }
 
     /**
@@ -190,43 +194,43 @@
     public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,
             OnContextClickListener {
 
-        public boolean onSingleTapUp(MotionEvent e) {
+        public boolean onSingleTapUp(@NonNull MotionEvent e) {
             return false;
         }
 
-        public void onLongPress(MotionEvent e) {
+        public void onLongPress(@NonNull MotionEvent e) {
         }
 
-        public boolean onScroll(MotionEvent e1, MotionEvent e2,
+        public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2,
                 float distanceX, float distanceY) {
             return false;
         }
 
-        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+        public boolean onFling(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float velocityX,
                 float velocityY) {
             return false;
         }
 
-        public void onShowPress(MotionEvent e) {
+        public void onShowPress(@NonNull MotionEvent e) {
         }
 
-        public boolean onDown(MotionEvent e) {
+        public boolean onDown(@NonNull MotionEvent e) {
             return false;
         }
 
-        public boolean onDoubleTap(MotionEvent e) {
+        public boolean onDoubleTap(@NonNull MotionEvent e) {
             return false;
         }
 
-        public boolean onDoubleTapEvent(MotionEvent e) {
+        public boolean onDoubleTapEvent(@NonNull MotionEvent e) {
             return false;
         }
 
-        public boolean onSingleTapConfirmed(MotionEvent e) {
+        public boolean onSingleTapConfirmed(@NonNull MotionEvent e) {
             return false;
         }
 
-        public boolean onContextClick(MotionEvent e) {
+        public boolean onContextClick(@NonNull MotionEvent e) {
             return false;
         }
     }
@@ -348,14 +352,13 @@
      * not be null.
      * @param handler the handler to use
      *
-     * @throws NullPointerException if either {@code listener} or
-     * {@code handler} is null.
+     * @throws NullPointerException if {@code listener} is null.
      *
      * @deprecated Use {@link #GestureDetector(android.content.Context,
      *      android.view.GestureDetector.OnGestureListener, android.os.Handler)} instead.
      */
     @Deprecated
-    public GestureDetector(OnGestureListener listener, Handler handler) {
+    public GestureDetector(@NonNull OnGestureListener listener, @Nullable Handler handler) {
         this(null, listener, handler);
     }
 
@@ -373,7 +376,7 @@
      *      android.view.GestureDetector.OnGestureListener)} instead.
      */
     @Deprecated
-    public GestureDetector(OnGestureListener listener) {
+    public GestureDetector(@NonNull OnGestureListener listener) {
         this(null, listener, null);
     }
 
@@ -392,7 +395,8 @@
      * @throws NullPointerException if {@code listener} is null.
      */
     // TODO(b/182007470): Use @ConfigurationContext instead
-    public GestureDetector(@UiContext Context context, OnGestureListener listener) {
+    public GestureDetector(@Nullable @UiContext Context context,
+            @NonNull OnGestureListener listener) {
         this(context, listener, null);
     }
 
@@ -411,8 +415,8 @@
      *
      * @throws NullPointerException if {@code listener} is null.
      */
-    public GestureDetector(@UiContext Context context, OnGestureListener listener,
-            Handler handler) {
+    public GestureDetector(@Nullable @UiContext Context context,
+            @NonNull OnGestureListener listener, @Nullable Handler handler) {
         if (handler != null) {
             mHandler = new GestureHandler(handler);
         } else {
@@ -442,8 +446,8 @@
      *
      * @throws NullPointerException if {@code listener} is null.
      */
-    public GestureDetector(@UiContext Context context, OnGestureListener listener, Handler handler,
-            boolean unused) {
+    public GestureDetector(@Nullable @UiContext Context context,
+            @NonNull OnGestureListener listener, @Nullable Handler handler, boolean unused) {
         this(context, listener, handler);
     }
 
@@ -486,7 +490,7 @@
      * @param onDoubleTapListener the listener invoked for all the callbacks, or
      *        null to stop listening for double-tap gestures.
      */
-    public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) {
+    public void setOnDoubleTapListener(@Nullable OnDoubleTapListener onDoubleTapListener) {
         mDoubleTapListener = onDoubleTapListener;
     }
 
@@ -496,7 +500,7 @@
      * @param onContextClickListener the listener invoked for all the callbacks, or null to stop
      *            listening for context clicks.
      */
-    public void setContextClickListener(OnContextClickListener onContextClickListener) {
+    public void setContextClickListener(@Nullable OnContextClickListener onContextClickListener) {
         mContextClickListener = onContextClickListener;
     }
 
@@ -528,7 +532,7 @@
      * @return true if the {@link OnGestureListener} consumed the event,
      *              else false.
      */
-    public boolean onTouchEvent(MotionEvent ev) {
+    public boolean onTouchEvent(@NonNull MotionEvent ev) {
         if (mInputEventConsistencyVerifier != null) {
             mInputEventConsistencyVerifier.onTouchEvent(ev, 0);
         }
@@ -800,7 +804,7 @@
      * @return true if the {@link OnGestureListener} consumed the event,
      *              else false.
      */
-    public boolean onGenericMotionEvent(MotionEvent ev) {
+    public boolean onGenericMotionEvent(@NonNull MotionEvent ev) {
         if (mInputEventConsistencyVerifier != null) {
             mInputEventConsistencyVerifier.onGenericMotionEvent(ev, 0);
         }
@@ -860,8 +864,8 @@
         mIgnoreNextUpEvent = false;
     }
 
-    private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp,
-            MotionEvent secondDown) {
+    private boolean isConsideredDoubleTap(@NonNull MotionEvent firstDown,
+            @NonNull MotionEvent firstUp, @NonNull MotionEvent secondDown) {
         if (!mAlwaysInBiggerTapRegion) {
             return false;
         }
diff --git a/core/java/android/view/Gravity.java b/core/java/android/view/Gravity.java
index c8bfd36..b4cdc6e 100644
--- a/core/java/android/view/Gravity.java
+++ b/core/java/android/view/Gravity.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.graphics.Rect;
 
 import java.lang.annotation.Retention;
@@ -187,8 +188,8 @@
      * @see View#LAYOUT_DIRECTION_LTR
      * @see View#LAYOUT_DIRECTION_RTL
      */
-    public static void apply(int gravity, int w, int h, Rect container,
-            Rect outRect, int layoutDirection) {
+    public static void apply(int gravity, int w, int h, @NonNull Rect container,
+            @NonNull Rect outRect, int layoutDirection) {
         int absGravity = getAbsoluteGravity(gravity, layoutDirection);
         apply(absGravity, w, h, container, 0, 0, outRect);
     }
@@ -214,8 +215,8 @@
      * @param outRect Receives the computed frame of the object in its
      *                container.
      */
-    public static void apply(int gravity, int w, int h, Rect container,
-            int xAdj, int yAdj, Rect outRect) {
+    public static void apply(int gravity, int w, int h, @NonNull Rect container,
+            int xAdj, int yAdj, @NonNull Rect outRect) {
         switch (gravity&((AXIS_PULL_BEFORE|AXIS_PULL_AFTER)<<AXIS_X_SHIFT)) {
             case 0:
                 outRect.left = container.left
@@ -324,8 +325,8 @@
      * @see View#LAYOUT_DIRECTION_LTR
      * @see View#LAYOUT_DIRECTION_RTL
      */
-    public static void apply(int gravity, int w, int h, Rect container,
-                             int xAdj, int yAdj, Rect outRect, int layoutDirection) {
+    public static void apply(int gravity, int w, int h, @NonNull Rect container,
+                             int xAdj, int yAdj, @NonNull Rect outRect, int layoutDirection) {
         int absGravity = getAbsoluteGravity(gravity, layoutDirection);
         apply(absGravity, w, h, container, xAdj, yAdj, outRect);
     }
@@ -346,7 +347,7 @@
      * @param inoutObj Supplies the current object position; returns with it
      * modified if needed to fit in the display.
      */
-    public static void applyDisplay(int gravity, Rect display, Rect inoutObj) {
+    public static void applyDisplay(int gravity, @NonNull Rect display, @NonNull Rect inoutObj) {
         if ((gravity&DISPLAY_CLIP_VERTICAL) != 0) {
             if (inoutObj.top < display.top) inoutObj.top = display.top;
             if (inoutObj.bottom > display.bottom) inoutObj.bottom = display.bottom;
@@ -404,7 +405,8 @@
      * @see View#LAYOUT_DIRECTION_LTR
      * @see View#LAYOUT_DIRECTION_RTL
      */
-    public static void applyDisplay(int gravity, Rect display, Rect inoutObj, int layoutDirection) {
+    public static void applyDisplay(int gravity, @NonNull Rect display, @NonNull Rect inoutObj,
+            int layoutDirection) {
         int absGravity = getAbsoluteGravity(gravity, layoutDirection);
         applyDisplay(absGravity, display, inoutObj);
     }
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index a2fb596..bc46d55 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -91,7 +91,7 @@
          * @return Return true to consume this click and prevent others from
          *         executing.
          */
-        public boolean onMenuItemClick(MenuItem item);
+        public boolean onMenuItemClick(@NonNull MenuItem item);
     }
 
     /**
@@ -110,7 +110,7 @@
          * @param item Item that was expanded
          * @return true if the item should expand, false if expansion should be suppressed.
          */
-        public boolean onMenuItemActionExpand(MenuItem item);
+        public boolean onMenuItemActionExpand(@NonNull MenuItem item);
 
         /**
          * Called when a menu item with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}
@@ -118,7 +118,7 @@
          * @param item Item that was collapsed
          * @return true if the item should collapse, false if collapsing should be suppressed.
          */
-        public boolean onMenuItemActionCollapse(MenuItem item);
+        public boolean onMenuItemActionCollapse(@NonNull MenuItem item);
     }
 
     /**
@@ -159,7 +159,7 @@
      * @param title The new text to be displayed.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setTitle(CharSequence title);
+    public @NonNull MenuItem setTitle(@Nullable CharSequence title);
 
     /**
      * Change the title associated with this item.
@@ -173,14 +173,14 @@
      * @see #setTitleCondensed(CharSequence)
      */
     
-    public MenuItem setTitle(@StringRes int title);
+    public @NonNull MenuItem setTitle(@StringRes int title);
 
     /**
      * Retrieve the current title of the item.
      *
      * @return The title.
      */
-    public CharSequence getTitle();
+    public @Nullable CharSequence getTitle();
 
     /**
      * Change the condensed title associated with this item. The condensed
@@ -190,7 +190,7 @@
      * @param title The new text to be displayed as the condensed title.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setTitleCondensed(CharSequence title);
+    public @NonNull MenuItem setTitleCondensed(@Nullable CharSequence title);
 
     /**
      * Retrieve the current condensed title of the item. If a condensed
@@ -199,7 +199,7 @@
      * @return The condensed title, if it exists.
      *         Otherwise the normal title.
      */
-    public CharSequence getTitleCondensed();
+    public @Nullable CharSequence getTitleCondensed();
 
     /**
      * Change the icon associated with this item. This icon will not always be
@@ -209,7 +209,7 @@
      * @param icon The new icon (as a Drawable) to be displayed.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setIcon(Drawable icon);
+    public @NonNull MenuItem setIcon(@Nullable Drawable icon);
 
     /**
      * Change the icon associated with this item. This icon will not always be
@@ -222,7 +222,7 @@
      * @param iconRes The new icon (as a resource ID) to be displayed.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setIcon(@DrawableRes int iconRes);
+    public @NonNull MenuItem setIcon(@DrawableRes int iconRes);
     
     /**
      * Returns the icon for this item as a Drawable (getting it from resources if it hasn't been
@@ -233,7 +233,7 @@
      * 
      * @return The icon as a Drawable.
      */
-    public Drawable getIcon();
+    public @Nullable Drawable getIcon();
 
     /**
      * Applies a tint to this item's icon. Does not modify the
@@ -250,15 +250,14 @@
      * @see #getIconTintList()
      * @see Drawable#setTintList(ColorStateList)
      */
-    public default MenuItem setIconTintList(@Nullable ColorStateList tint) { return this; }
+    public default @NonNull MenuItem setIconTintList(@Nullable ColorStateList tint) { return this; }
 
     /**
      * @return the tint applied to this item's icon
      * @attr ref android.R.styleable#MenuItem_iconTint
      * @see #setIconTintList(ColorStateList)
      */
-    @Nullable
-    public default ColorStateList getIconTintList() { return null; }
+    public default @Nullable ColorStateList getIconTintList() { return null; }
 
     /**
      * Specifies the blending mode used to apply the tint specified by
@@ -304,8 +303,7 @@
      * @see #setIconTintBlendMode(BlendMode)
      *
      */
-    @Nullable
-    public default PorterDuff.Mode getIconTintMode() { return null; }
+    public default @Nullable PorterDuff.Mode getIconTintMode() { return null; }
 
     /**
      * Returns the blending mode used to apply the tint to this item's icon, if specified.
@@ -315,8 +313,7 @@
      * @see #setIconTintBlendMode(BlendMode)
      *
      */
-    @Nullable
-    default BlendMode getIconTintBlendMode() {
+    default @Nullable BlendMode getIconTintBlendMode() {
         PorterDuff.Mode mode = getIconTintMode();
         if (mode != null) {
             return BlendMode.fromValue(mode.nativeInt);
@@ -343,7 +340,7 @@
      *               modify it later.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setIntent(Intent intent);
+    public @NonNull MenuItem setIntent(@Nullable Intent intent);
 
     /**
      * Return the Intent associated with this item.  This returns a
@@ -354,7 +351,7 @@
      * @return Returns the last value supplied to {@link #setIntent}, or
      *         null.
      */
-    public Intent getIntent();
+    public @Nullable Intent getIntent();
 
     /**
      * Change both the numeric and alphabetic shortcut associated with this
@@ -372,7 +369,7 @@
      *        using a keyboard with alphabetic keys.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setShortcut(char numericChar, char alphaChar);
+    public @NonNull MenuItem setShortcut(char numericChar, char alphaChar);
 
     /**
      * Change both the numeric and alphabetic shortcut associated with this
@@ -397,8 +394,8 @@
      *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
      * @return This Item so additional setters can be called.
      */
-    default public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
-            int alphaModifiers) {
+    default public @NonNull MenuItem setShortcut(char numericChar, char alphaChar,
+            int numericModifiers, int alphaModifiers) {
         if ((alphaModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON
                 && (numericModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON) {
             return setShortcut(numericChar, alphaChar);
@@ -416,7 +413,7 @@
      *                 using a 12-key (numeric) keyboard.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setNumericShortcut(char numericChar);
+    public @NonNull MenuItem setNumericShortcut(char numericChar);
 
     /**
      * Change the numeric shortcut and modifiers associated with this item.
@@ -431,7 +428,7 @@
      *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
      * @return This Item so additional setters can be called.
      */
-    default public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
+    default public @NonNull MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
         if ((numericModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON) {
             return setNumericShortcut(numericChar);
         } else {
@@ -475,7 +472,7 @@
      *        using a keyboard with alphabetic keys.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setAlphabeticShortcut(char alphaChar);
+    public @NonNull MenuItem setAlphabeticShortcut(char alphaChar);
 
     /**
      * Change the alphabetic shortcut associated with this item. The shortcut
@@ -495,7 +492,7 @@
      *        {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}.
      * @return This Item so additional setters can be called.
      */
-    default public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) {
+    default public @NonNull MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) {
         if ((alphaModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON) {
             return setAlphabeticShortcut(alphaChar);
         } else {
@@ -539,7 +536,7 @@
      * @see Menu#setGroupCheckable
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setCheckable(boolean checkable);
+    public @NonNull MenuItem setCheckable(boolean checkable);
 
     /**
      * Return whether the item can currently display a check mark.
@@ -566,7 +563,7 @@
      *                it.  The default value is false.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setChecked(boolean checked);
+    public @NonNull MenuItem setChecked(boolean checked);
 
     /**
      * Return whether the item is currently displaying a check mark.
@@ -586,7 +583,7 @@
      *        hidden.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setVisible(boolean visible);
+    public @NonNull MenuItem setVisible(boolean visible);
 
     /**
      * Return the visibility of the menu item.
@@ -604,7 +601,7 @@
      *        won't be invokable.
      * @return This Item so additional setters can be called.
      */
-    public MenuItem setEnabled(boolean enabled);
+    public @NonNull MenuItem setEnabled(boolean enabled);
 
     /**
      * Return the enabled state of the menu item.
@@ -628,7 +625,7 @@
      *
      * @return The associated menu if there is one, else null
      */
-    public SubMenu getSubMenu();
+    public @Nullable SubMenu getSubMenu();
 
     /**
      * Set a custom listener for invocation of this menu item. In most
@@ -641,7 +638,8 @@
      * @see Activity#onOptionsItemSelected(MenuItem)
      * @see Activity#onContextItemSelected(MenuItem)
      */
-    public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener menuItemClickListener);
+    public @NonNull MenuItem setOnMenuItemClickListener(
+            @Nullable MenuItem.OnMenuItemClickListener menuItemClickListener);
 
     /**
      * Gets the extra information linked to this menu item.  This extra
@@ -652,7 +650,7 @@
      * @return The extra information linked to the View that added this
      *         menu item to the menu. This can be null.
      */
-    public ContextMenuInfo getMenuInfo();
+    public @Nullable ContextMenuInfo getMenuInfo();
     
     /**
      * Sets how this item should display in the presence of an Action Bar.
@@ -690,7 +688,7 @@
      * @see #setActionView(View)
      * @return This MenuItem instance for call chaining.
      */
-    public MenuItem setShowAsActionFlags(int actionEnum);
+    public @NonNull MenuItem setShowAsActionFlags(int actionEnum);
 
     /**
      * Set an action view for this menu item. An action view will be displayed in place
@@ -706,7 +704,7 @@
      *
      * @see #setShowAsAction(int)
      */
-    public MenuItem setActionView(View view);
+    public @NonNull MenuItem setActionView(@Nullable View view);
 
     /**
      * Set an action view for this menu item. An action view will be displayed in place
@@ -722,7 +720,7 @@
      *
      * @see #setShowAsAction(int)
      */
-    public MenuItem setActionView(@LayoutRes int resId);
+    public @NonNull MenuItem setActionView(@LayoutRes int resId);
 
     /**
      * Returns the currently set action view for this menu item.
@@ -732,7 +730,7 @@
      * @see #setActionView(View)
      * @see #setShowAsAction(int)
      */
-    public View getActionView();
+    public @Nullable View getActionView();
 
     /**
      * Sets the {@link ActionProvider} responsible for creating an action view if
@@ -748,7 +746,7 @@
      *
      * @see ActionProvider
      */
-    public MenuItem setActionProvider(ActionProvider actionProvider);
+    public @NonNull MenuItem setActionProvider(@Nullable ActionProvider actionProvider);
 
     /**
      * Gets the {@link ActionProvider}.
@@ -758,7 +756,7 @@
      * @see ActionProvider
      * @see #setActionProvider(ActionProvider)
      */
-    public ActionProvider getActionProvider();
+    public @Nullable ActionProvider getActionProvider();
 
     /**
      * Expand the action view associated with this menu item.
@@ -806,14 +804,14 @@
      * @param listener Listener that will respond to expand/collapse events
      * @return This menu item instance for call chaining
      */
-    public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
+    public @NonNull MenuItem setOnActionExpandListener(@Nullable OnActionExpandListener listener);
 
     /**
      * Change the content description associated with this menu item.
      *
      * @param contentDescription The new content description.
      */
-    default MenuItem setContentDescription(CharSequence contentDescription) {
+    default @NonNull MenuItem setContentDescription(@Nullable CharSequence contentDescription) {
         return this;
     }
 
@@ -822,7 +820,7 @@
      *
      * @return The content description.
      */
-    default CharSequence getContentDescription() {
+    default @Nullable CharSequence getContentDescription() {
         return null;
     }
 
@@ -831,7 +829,7 @@
      *
      * @param tooltipText The new tooltip text.
      */
-    default MenuItem setTooltipText(CharSequence tooltipText) {
+    default @NonNull MenuItem setTooltipText(@Nullable CharSequence tooltipText) {
         return this;
     }
 
@@ -840,7 +838,7 @@
      *
      * @return The tooltip text.
      */
-    default CharSequence getTooltipText() {
+    default @Nullable CharSequence getTooltipText() {
         return null;
     }
 
diff --git a/core/java/android/view/OnBackInvokedDispatcher.java b/core/java/android/view/OnBackInvokedDispatcher.java
index 05c312b..5c4ee89 100644
--- a/core/java/android/view/OnBackInvokedDispatcher.java
+++ b/core/java/android/view/OnBackInvokedDispatcher.java
@@ -17,8 +17,14 @@
 package android.view;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import android.os.Build;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -31,25 +37,56 @@
  * Attribute updates are proactively pushed to the window manager if they change the dispatch
  * target (a.k.a. the callback to be invoked next), or its behavior.
  */
-public abstract class OnBackInvokedDispatcher {
+public interface OnBackInvokedDispatcher {
+    /**
+     * Enables dispatching the "back" action via {@link android.view.OnBackInvokedDispatcher}.
+     *
+     * When enabled, the following APIs are no longer invoked:
+     * <ul>
+     * <li> {@link android.app.Activity#onBackPressed}
+     * <li> {@link android.app.Dialog#onBackPressed}
+     * <li> {@link android.view.KeyEvent#KEYCODE_BACK} is no longer dispatched.
+     * </ul>
+     *
+     * @hide
+     */
+    @TestApi
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+    long DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME = 195946584L;
+
+    /** @hide */
+    String TAG = "OnBackInvokedDispatcher";
+
+    /** @hide */
+    boolean DEBUG = Build.isDebuggable();
+
     /** @hide */
     @IntDef({
             PRIORITY_DEFAULT,
             PRIORITY_OVERLAY,
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface Priority{}
+    @interface Priority{}
 
     /**
      * Priority level of {@link OnBackInvokedCallback}s for overlays such as menus and
      * navigation drawers that should receive back dispatch before non-overlays.
      */
-    public static final int PRIORITY_OVERLAY = 1000000;
+    int PRIORITY_OVERLAY = 1000000;
 
     /**
      * Default priority level of {@link OnBackInvokedCallback}s.
      */
-    public static final int PRIORITY_DEFAULT = 0;
+    int PRIORITY_DEFAULT = 0;
+
+    /**
+     * Priority level of {@link OnBackInvokedCallback}s registered by the system.
+     *
+     * System back animation will play when the callback to receive dispatch has this priority.
+     * @hide
+     */
+    int PRIORITY_SYSTEM = -1;
 
     /**
      * Registers a {@link OnBackInvokedCallback}.
@@ -61,10 +98,11 @@
      *                 registered, the existing instance (no matter its priority) will be
      *                 unregistered and registered again.
      * @param priority The priority of the callback.
+     * @throws {@link IllegalArgumentException} if the priority is negative.
      */
     @SuppressLint("SamShouldBeLast")
-    public abstract void registerOnBackInvokedCallback(
-            @NonNull OnBackInvokedCallback callback, @Priority int priority);
+    void registerOnBackInvokedCallback(
+            @NonNull OnBackInvokedCallback callback, @Priority @IntRange(from = 0) int priority);
 
     /**
      * Unregisters a {@link OnBackInvokedCallback}.
@@ -72,5 +110,20 @@
      * @param callback The callback to be unregistered. Does nothing if the callback has not been
      *                 registered.
      */
-    public abstract void unregisterOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback);
+    void unregisterOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback);
+
+    /**
+     * Returns the most prioritized callback to receive back dispatch next.
+     * @hide
+     */
+    @Nullable
+    default OnBackInvokedCallback getTopCallback() {
+        return null;
+    }
+
+    /**
+     * Registers a {@link OnBackInvokedCallback} with system priority.
+     * @hide
+     */
+    default void registerSystemOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback) { }
 }
diff --git a/core/java/android/view/OnBackInvokedDispatcherOwner.java b/core/java/android/view/OnBackInvokedDispatcherOwner.java
index 0e14ed4..e69efe0 100644
--- a/core/java/android/view/OnBackInvokedDispatcherOwner.java
+++ b/core/java/android/view/OnBackInvokedDispatcherOwner.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import android.annotation.Nullable;
+import android.annotation.NonNull;
 
 /**
  * A class that provides an {@link OnBackInvokedDispatcher} that allows you to register
@@ -28,6 +28,6 @@
      * to its registered {@link OnBackInvokedCallback}s.
      * Returns null when the root view is not attached to a window or a view tree with a decor.
      */
-    @Nullable
+    @NonNull
     OnBackInvokedDispatcher getOnBackInvokedDispatcher();
 }
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 38ae03d..2a8e7e4 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -184,7 +184,7 @@
      * @see #TYPE_NULL
      * @hide
      */
-    public static PointerIcon getNullIcon() {
+    public static @NonNull PointerIcon getNullIcon() {
         return gNullIcon;
     }
 
@@ -197,7 +197,7 @@
      * @throws IllegalArgumentException if context is null.
      * @hide
      */
-    public static PointerIcon getDefaultIcon(@NonNull Context context) {
+    public static @NonNull PointerIcon getDefaultIcon(@NonNull Context context) {
         return getSystemIcon(context, TYPE_DEFAULT);
     }
 
@@ -211,7 +211,7 @@
      *
      * @throws IllegalArgumentException if context is null.
      */
-    public static PointerIcon getSystemIcon(@NonNull Context context, int type) {
+    public static @NonNull PointerIcon getSystemIcon(@NonNull Context context, int type) {
         if (context == null) {
             throw new IllegalArgumentException("context must not be null");
         }
@@ -287,7 +287,8 @@
      * @throws IllegalArgumentException if bitmap is null, or if the x/y hotspot
      *         parameters are invalid.
      */
-    public static PointerIcon create(@NonNull Bitmap bitmap, float hotSpotX, float hotSpotY) {
+    public static @NonNull PointerIcon create(@NonNull Bitmap bitmap, float hotSpotX,
+            float hotSpotY) {
         if (bitmap == null) {
             throw new IllegalArgumentException("bitmap must not be null");
         }
@@ -321,7 +322,7 @@
      * @throws Resources.NotFoundException if the resource was not found or the drawable
      * linked in the resource was not found.
      */
-    public static PointerIcon load(@NonNull Resources resources, @XmlRes int resourceId) {
+    public static @NonNull PointerIcon load(@NonNull Resources resources, @XmlRes int resourceId) {
         if (resources == null) {
             throw new IllegalArgumentException("resources must not be null");
         }
@@ -342,7 +343,7 @@
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public PointerIcon load(@NonNull Context context) {
+    public @NonNull PointerIcon load(@NonNull Context context) {
         if (context == null) {
             throw new IllegalArgumentException("context must not be null");
         }
@@ -362,7 +363,7 @@
         return mType;
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<PointerIcon> CREATOR
+    public static final @NonNull Parcelable.Creator<PointerIcon> CREATOR
             = new Parcelable.Creator<PointerIcon>() {
         public PointerIcon createFromParcel(Parcel in) {
             int type = in.readInt();
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 346f76c..a0a172d 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.os.Build;
@@ -67,7 +69,7 @@
          *          only wants to update scaling factors if the change is
          *          greater than 0.01.
          */
-        public boolean onScale(ScaleGestureDetector detector);
+        public boolean onScale(@NonNull ScaleGestureDetector detector);
 
         /**
          * Responds to the beginning of a scaling gesture. Reported by
@@ -81,7 +83,7 @@
          *          sense, onScaleBegin() may return false to ignore the
          *          rest of the gesture.
          */
-        public boolean onScaleBegin(ScaleGestureDetector detector);
+        public boolean onScaleBegin(@NonNull ScaleGestureDetector detector);
 
         /**
          * Responds to the end of a scale gesture. Reported by existing
@@ -94,7 +96,7 @@
          * @param detector The detector reporting the event - use this to
          *          retrieve extended info about event state.
          */
-        public void onScaleEnd(ScaleGestureDetector detector);
+        public void onScaleEnd(@NonNull ScaleGestureDetector detector);
     }
 
     /**
@@ -109,15 +111,15 @@
      */
     public static class SimpleOnScaleGestureListener implements OnScaleGestureListener {
 
-        public boolean onScale(ScaleGestureDetector detector) {
+        public boolean onScale(@NonNull ScaleGestureDetector detector) {
             return false;
         }
 
-        public boolean onScaleBegin(ScaleGestureDetector detector) {
+        public boolean onScaleBegin(@NonNull ScaleGestureDetector detector) {
             return true;
         }
 
-        public void onScaleEnd(ScaleGestureDetector detector) {
+        public void onScaleEnd(@NonNull ScaleGestureDetector detector) {
             // Intentionally empty
         }
     }
@@ -180,7 +182,8 @@
      *
      * @throws NullPointerException if {@code listener} is null.
      */
-    public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
+    public ScaleGestureDetector(@NonNull Context context,
+            @NonNull OnScaleGestureListener listener) {
         this(context, listener, null);
     }
 
@@ -195,8 +198,8 @@
      *
      * @throws NullPointerException if {@code listener} is null.
      */
-    public ScaleGestureDetector(Context context, OnScaleGestureListener listener,
-                                Handler handler) {
+    public ScaleGestureDetector(@NonNull Context context, @NonNull OnScaleGestureListener listener,
+                                @Nullable Handler handler) {
         mContext = context;
         mListener = listener;
         final ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
@@ -226,7 +229,7 @@
      * @return true if the event was processed and the detector wants to receive the
      *         rest of the MotionEvents in this event stream.
      */
-    public boolean onTouchEvent(MotionEvent event) {
+    public boolean onTouchEvent(@NonNull MotionEvent event) {
         if (mInputEventConsistencyVerifier != null) {
             mInputEventConsistencyVerifier.onTouchEvent(event, 0);
         }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6f5fea2..8f8c5a9 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -2731,6 +2731,17 @@
     }
 
     /**
+     * Interface to handle request to
+     * {@link SurfaceControl.Transaction#addTransactionCommittedListener(Executor, TransactionCommittedListener)}
+     */
+    public interface TransactionCommittedListener {
+        /**
+         * Invoked when the transaction has been committed in SurfaceFlinger.
+         */
+        void onTransactionCommitted();
+    }
+
+    /**
      * An atomic set of changes to a set of SurfaceControl.
      */
     public static class Transaction implements Closeable, Parcelable {
diff --git a/core/java/android/view/TransactionCommittedListener.java b/core/java/android/view/TransactionCommittedListener.java
deleted file mode 100644
index 6abded2..0000000
--- a/core/java/android/view/TransactionCommittedListener.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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;
-
-import java.util.concurrent.Executor;
-
-/**
- * Interface to handle request to
- * {@link SurfaceControl.Transaction#addTransactionCommittedListener(Executor, TransactionCommittedListener)}
- */
-public interface TransactionCommittedListener {
-    /**
-     * Invoked when the transaction has been committed in SurfaceFlinger.
-     */
-    void onTransactionCommitted();
-}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4ff7e229..70689bd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -834,7 +834,7 @@
  */
 @UiThread
 public class View implements Drawable.Callback, KeyEvent.Callback,
-        AccessibilityEventSource, OnBackInvokedDispatcherOwner {
+        AccessibilityEventSource {
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private static final boolean DBG = false;
 
@@ -8608,7 +8608,7 @@
      *
      * @hide
      */
-    public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() {
+    public @Nullable AccessibilityNodeInfo createAccessibilityNodeInfoInternal() {
         AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
         if (provider != null) {
             return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID);
@@ -12290,7 +12290,7 @@
 
     /**
      * @return whether this view should have haptic feedback enabled for events
-     * long presses.
+     * such as long presses.
      *
      * @see #setHapticFeedbackEnabled(boolean)
      * @see #performHapticFeedback(int)
@@ -14226,7 +14226,8 @@
      * @param arguments Optional action arguments
      * @return true if the action was consumed by a parent
      */
-    public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) {
+    public boolean dispatchNestedPrePerformAccessibilityAction(int action,
+            @Nullable Bundle arguments) {
         for (ViewParent p = getParent(); p != null; p = p.getParent()) {
             if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) {
                 return true;
@@ -14254,7 +14255,7 @@
      * @param arguments Optional action arguments.
      * @return Whether the action was performed.
      */
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
+    public boolean performAccessibilityAction(int action, @Nullable Bundle arguments) {
       if (mAccessibilityDelegate != null) {
           return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments);
       } else {
@@ -14270,7 +14271,7 @@
     * @hide
     */
     @UnsupportedAppUsage
-    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+    public boolean performAccessibilityActionInternal(int action, @Nullable Bundle arguments) {
         if (isNestedScrollingEnabled()
                 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
                 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
@@ -29268,12 +29269,12 @@
          * Called when the view is attached to a window.
          * @param v The view that was attached
          */
-        public void onViewAttachedToWindow(View v);
+        public void onViewAttachedToWindow(@NonNull View v);
         /**
          * Called when the view is detached from a window.
          * @param v The view that was detached
          */
-        public void onViewDetachedFromWindow(View v);
+        public void onViewDetachedFromWindow(@NonNull View v);
     }
 
     /**
@@ -29298,7 +29299,8 @@
          * @param insets The insets to apply
          * @return The insets supplied, minus any insets that were consumed
          */
-        public WindowInsets onApplyWindowInsets(View v, WindowInsets insets);
+        public @NonNull WindowInsets onApplyWindowInsets(@NonNull View v,
+                @NonNull WindowInsets insets);
     }
 
     private final class UnsetPressedState implements Runnable {
@@ -30241,7 +30243,7 @@
          *
          * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
          */
-        public void sendAccessibilityEvent(View host, int eventType) {
+        public void sendAccessibilityEvent(@NonNull View host, int eventType) {
             host.sendAccessibilityEventInternal(eventType);
         }
 
@@ -30261,7 +30263,8 @@
          * @see View#performAccessibilityAction(int, Bundle)
          *      View#performAccessibilityAction(int, Bundle)
          */
-        public boolean performAccessibilityAction(View host, int action, Bundle args) {
+        public boolean performAccessibilityAction(@NonNull View host, int action,
+                @Nullable Bundle args) {
             return host.performAccessibilityActionInternal(action, args);
         }
 
@@ -30283,7 +30286,8 @@
          * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent)
          *      View#sendAccessibilityEventUnchecked(AccessibilityEvent)
          */
-        public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
+        public void sendAccessibilityEventUnchecked(@NonNull View host,
+                @NonNull AccessibilityEvent event) {
             host.sendAccessibilityEventUncheckedInternal(event);
         }
 
@@ -30304,7 +30308,8 @@
          * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
          *      View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
          */
-        public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+        public boolean dispatchPopulateAccessibilityEvent(@NonNull View host,
+                @NonNull AccessibilityEvent event) {
             return host.dispatchPopulateAccessibilityEventInternal(event);
         }
 
@@ -30324,7 +30329,8 @@
          * @see View#onPopulateAccessibilityEvent(AccessibilityEvent)
          *      View#onPopulateAccessibilityEvent(AccessibilityEvent)
          */
-        public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+        public void onPopulateAccessibilityEvent(@NonNull View host,
+                @NonNull AccessibilityEvent event) {
             host.onPopulateAccessibilityEventInternal(event);
         }
 
@@ -30344,7 +30350,8 @@
          * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
          *      View#onInitializeAccessibilityEvent(AccessibilityEvent)
          */
-        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+        public void onInitializeAccessibilityEvent(@NonNull View host,
+                @NonNull AccessibilityEvent event) {
             host.onInitializeAccessibilityEventInternal(event);
         }
 
@@ -30363,7 +30370,8 @@
          * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
          *      View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
          */
-        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+        public void onInitializeAccessibilityNodeInfo(@NonNull View host,
+                @NonNull AccessibilityNodeInfo info) {
             host.onInitializeAccessibilityNodeInfoInternal(info);
         }
 
@@ -30415,8 +30423,8 @@
          * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
          *      ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)
          */
-        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
-                AccessibilityEvent event) {
+        public boolean onRequestSendAccessibilityEvent(@NonNull ViewGroup host, @NonNull View child,
+                @NonNull AccessibilityEvent event) {
             return host.onRequestSendAccessibilityEventInternal(child, event);
         }
 
@@ -30434,7 +30442,8 @@
          *
          * @see AccessibilityNodeProvider
          */
-        public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
+        public @Nullable AccessibilityNodeProvider getAccessibilityNodeProvider(
+                @NonNull View host) {
             return null;
         }
 
@@ -30462,7 +30471,7 @@
          * @hide
          */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-        public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) {
+        public AccessibilityNodeInfo createAccessibilityNodeInfo(@NonNull View host) {
             return host.createAccessibilityNodeInfoInternal();
         }
     }
@@ -31447,23 +31456,4 @@
         }
         return null;
     }
-
-    /**
-     * Returns the {@link OnBackInvokedDispatcher} instance of the window this view is attached to.
-     *
-     * @return The {@link OnBackInvokedDispatcher} or {@code null} if the view is neither attached
-     *         to a window or a view tree with a decor.
-     */
-    @Nullable
-    public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
-        ViewParent parent = getParent();
-        if (parent instanceof View) {
-            return ((View) parent).getOnBackInvokedDispatcher();
-        } else if (parent instanceof ViewRootImpl) {
-            // Get the fallback dispatcher on {@link ViewRootImpl} if the view tree doesn't have
-            // a {@link com.android.internal.policy.DecorView}.
-            return ((ViewRootImpl) parent).getOnBackInvokedDispatcher();
-        }
-        return null;
-    }
 }
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 9ed42f3..b25c025 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.FloatRange;
+import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.annotation.UiContext;
 import android.app.Activity;
@@ -405,7 +406,7 @@
      * @see #get(android.content.Context)
      * @see android.util.DisplayMetrics
      */
-    private ViewConfiguration(@UiContext Context context) {
+    private ViewConfiguration(@NonNull @UiContext Context context) {
         mConstructedWithContext = true;
         final Resources res = context.getResources();
         final DisplayMetrics metrics = res.getDisplayMetrics();
@@ -517,7 +518,7 @@
      *                {@link Context#createWindowContext(int, Bundle)}.
      */
     // TODO(b/182007470): Use @ConfigurationContext instead
-    public static ViewConfiguration get(@UiContext Context context) {
+    public static ViewConfiguration get(@NonNull @UiContext Context context) {
         StrictMode.assertConfigurationContext(context, "ViewConfiguration");
 
         final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 49f5229..128da31 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Bundle;
@@ -298,7 +299,7 @@
      *
      * @param child The child whose drawable state has changed.
      */
-    public void childDrawableStateChanged(View child);
+    public void childDrawableStateChanged(@NonNull View child);
 
     /**
      * Called when a child does not want this parent and its ancestors to
@@ -337,7 +338,7 @@
      *        false otherwise
      * @return Whether the group scrolled to handle the operation
      */
-    public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
+    public boolean requestChildRectangleOnScreen(@NonNull View child, Rect rectangle,
             boolean immediate);
 
     /**
@@ -356,7 +357,7 @@
      * @param event The event to be sent.
      * @return True if the event was sent.
      */
-    public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event);
+    public boolean requestSendAccessibilityEvent(@NonNull View child, AccessibilityEvent event);
 
     /**
      * Called when a child view now has or no longer is tracking transient state.
@@ -381,7 +382,7 @@
      * @param child Child view whose state has changed
      * @param hasTransientState true if this child has transient state
      */
-    public void childHasTransientStateChanged(View child, boolean hasTransientState);
+    public void childHasTransientStateChanged(@NonNull View child, boolean hasTransientState);
 
     /**
      * Ask that a new dispatch of {@link View#fitSystemWindows(Rect)
@@ -418,7 +419,7 @@
      *            </ul>
      */
     public void notifySubtreeAccessibilityStateChanged(
-            View child, @NonNull View source, int changeType);
+            @NonNull View child, @NonNull View source, int changeType);
 
     /**
      * Tells if this view parent can resolve the layout direction.
@@ -525,7 +526,8 @@
      *                         {@link View#SCROLL_AXIS_VERTICAL} or both
      * @return true if this ViewParent accepts the nested scroll operation
      */
-    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes);
+    public boolean onStartNestedScroll(@NonNull View child, @NonNull View target,
+            int nestedScrollAxes);
 
     /**
      * React to the successful claiming of a nested scroll operation.
@@ -543,7 +545,8 @@
      * @see #onStartNestedScroll(View, View, int)
      * @see #onStopNestedScroll(View)
      */
-    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes);
+    public void onNestedScrollAccepted(@NonNull View child, @NonNull View target,
+            int nestedScrollAxes);
 
     /**
      * React to a nested scroll operation ending.
@@ -556,7 +559,7 @@
      *
      * @param target View that initiated the nested scroll
      */
-    public void onStopNestedScroll(View target);
+    public void onStopNestedScroll(@NonNull View target);
 
     /**
      * React to a nested scroll in progress.
@@ -579,7 +582,7 @@
      * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by target
      * @param dyUnconsumed Vertical scroll distance in pixels not consumed by target
      */
-    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
             int dxUnconsumed, int dyUnconsumed);
 
     /**
@@ -602,7 +605,7 @@
      * @param dy Vertical scroll distance in pixels
      * @param consumed Output. The horizontal and vertical scroll distance consumed by this parent
      */
-    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed);
+    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed);
 
     /**
      * Request a fling from a nested scroll.
@@ -623,7 +626,8 @@
      * @param consumed true if the child consumed the fling, false otherwise
      * @return true if this parent consumed or otherwise reacted to the fling
      */
-    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed);
+    public boolean onNestedFling(@NonNull View target, float velocityX, float velocityY,
+            boolean consumed);
 
     /**
      * React to a nested fling before the target view consumes it.
@@ -645,7 +649,7 @@
      * @param velocityY Vertical velocity in pixels per second
      * @return true if this parent consumed the fling ahead of the target view
      */
-    public boolean onNestedPreFling(View target, float velocityX, float velocityY);
+    public boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY);
 
     /**
      * React to an accessibility action delegated by a target descendant view before the target
@@ -664,7 +668,8 @@
      * @param arguments Optional action arguments
      * @return true if the action was consumed by this ViewParent
      */
-    public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle arguments);
+    public boolean onNestedPrePerformAccessibilityAction(@NonNull View target, int action,
+            @Nullable Bundle arguments);
 
     /**
      * Given a touchable region of a child, this method reduces region by the bounds of all views on
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 65cc2f8..774d697 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -20,6 +20,8 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.RenderNode;
 
 import java.util.ArrayList;
@@ -246,7 +248,7 @@
      *
      * @param view The View associated with this ViewPropertyAnimator
      */
-    ViewPropertyAnimator(View view) {
+    ViewPropertyAnimator(@NonNull View view) {
         mView = view;
         view.ensureTransformationInfo();
     }
@@ -259,7 +261,7 @@
      * cannot be negative.
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator setDuration(long duration) {
+    public @NonNull ViewPropertyAnimator setDuration(long duration) {
         if (duration < 0) {
             throw new IllegalArgumentException("Animators cannot have negative duration: " +
                     duration);
@@ -316,7 +318,7 @@
      * cannot be negative.
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator setStartDelay(long startDelay) {
+    public @NonNull ViewPropertyAnimator setStartDelay(long startDelay) {
         if (startDelay < 0) {
             throw new IllegalArgumentException("Animators cannot have negative start " +
                 "delay: " + startDelay);
@@ -335,7 +337,7 @@
      * of <code>null</code> will result in linear interpolation.
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
+    public @NonNull ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
         mInterpolatorSet = true;
         mInterpolator = interpolator;
         return this;
@@ -346,7 +348,7 @@
      *
      * @return The timing interpolator for this animation.
      */
-    public TimeInterpolator getInterpolator() {
+    public @Nullable TimeInterpolator getInterpolator() {
         if (mInterpolatorSet) {
             return mInterpolator;
         } else {
@@ -369,12 +371,12 @@
      * <code>null</code> removes any existing listener.
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
+    public @NonNull ViewPropertyAnimator setListener(@Nullable Animator.AnimatorListener listener) {
         mListener = listener;
         return this;
     }
 
-    Animator.AnimatorListener getListener() {
+    @Nullable Animator.AnimatorListener getListener() {
         return mListener;
     }
 
@@ -392,12 +394,13 @@
      * <code>null</code> removes any existing listener.
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
+    public @NonNull ViewPropertyAnimator setUpdateListener(
+            @Nullable ValueAnimator.AnimatorUpdateListener listener) {
         mUpdateListener = listener;
         return this;
     }
 
-    ValueAnimator.AnimatorUpdateListener getUpdateListener() {
+    @Nullable ValueAnimator.AnimatorUpdateListener getUpdateListener() {
         return mUpdateListener;
     }
 
@@ -441,7 +444,7 @@
      * @see View#setX(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator x(float value) {
+    public @NonNull ViewPropertyAnimator x(float value) {
         animateProperty(X, value);
         return this;
     }
@@ -454,7 +457,7 @@
      * @see View#setX(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator xBy(float value) {
+    public @NonNull ViewPropertyAnimator xBy(float value) {
         animatePropertyBy(X, value);
         return this;
     }
@@ -467,7 +470,7 @@
      * @see View#setY(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator y(float value) {
+    public @NonNull ViewPropertyAnimator y(float value) {
         animateProperty(Y, value);
         return this;
     }
@@ -480,7 +483,7 @@
      * @see View#setY(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator yBy(float value) {
+    public @NonNull ViewPropertyAnimator yBy(float value) {
         animatePropertyBy(Y, value);
         return this;
     }
@@ -493,7 +496,7 @@
      * @see View#setZ(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator z(float value) {
+    public @NonNull ViewPropertyAnimator z(float value) {
         animateProperty(Z, value);
         return this;
     }
@@ -506,7 +509,7 @@
      * @see View#setZ(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator zBy(float value) {
+    public @NonNull ViewPropertyAnimator zBy(float value) {
         animatePropertyBy(Z, value);
         return this;
     }
@@ -519,7 +522,7 @@
      * @see View#setRotation(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator rotation(float value) {
+    public @NonNull ViewPropertyAnimator rotation(float value) {
         animateProperty(ROTATION, value);
         return this;
     }
@@ -532,7 +535,7 @@
      * @see View#setRotation(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator rotationBy(float value) {
+    public @NonNull ViewPropertyAnimator rotationBy(float value) {
         animatePropertyBy(ROTATION, value);
         return this;
     }
@@ -545,7 +548,7 @@
      * @see View#setRotationX(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator rotationX(float value) {
+    public @NonNull ViewPropertyAnimator rotationX(float value) {
         animateProperty(ROTATION_X, value);
         return this;
     }
@@ -558,7 +561,7 @@
      * @see View#setRotationX(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator rotationXBy(float value) {
+    public @NonNull ViewPropertyAnimator rotationXBy(float value) {
         animatePropertyBy(ROTATION_X, value);
         return this;
     }
@@ -571,7 +574,7 @@
      * @see View#setRotationY(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator rotationY(float value) {
+    public @NonNull ViewPropertyAnimator rotationY(float value) {
         animateProperty(ROTATION_Y, value);
         return this;
     }
@@ -584,7 +587,7 @@
      * @see View#setRotationY(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator rotationYBy(float value) {
+    public @NonNull ViewPropertyAnimator rotationYBy(float value) {
         animatePropertyBy(ROTATION_Y, value);
         return this;
     }
@@ -597,7 +600,7 @@
      * @see View#setTranslationX(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator translationX(float value) {
+    public @NonNull ViewPropertyAnimator translationX(float value) {
         animateProperty(TRANSLATION_X, value);
         return this;
     }
@@ -610,7 +613,7 @@
      * @see View#setTranslationX(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator translationXBy(float value) {
+    public @NonNull ViewPropertyAnimator translationXBy(float value) {
         animatePropertyBy(TRANSLATION_X, value);
         return this;
     }
@@ -623,7 +626,7 @@
      * @see View#setTranslationY(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator translationY(float value) {
+    public @NonNull ViewPropertyAnimator translationY(float value) {
         animateProperty(TRANSLATION_Y, value);
         return this;
     }
@@ -636,7 +639,7 @@
      * @see View#setTranslationY(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator translationYBy(float value) {
+    public @NonNull ViewPropertyAnimator translationYBy(float value) {
         animatePropertyBy(TRANSLATION_Y, value);
         return this;
     }
@@ -649,7 +652,7 @@
      * @see View#setTranslationZ(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator translationZ(float value) {
+    public @NonNull ViewPropertyAnimator translationZ(float value) {
         animateProperty(TRANSLATION_Z, value);
         return this;
     }
@@ -662,7 +665,7 @@
      * @see View#setTranslationZ(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator translationZBy(float value) {
+    public @NonNull ViewPropertyAnimator translationZBy(float value) {
         animatePropertyBy(TRANSLATION_Z, value);
         return this;
     }
@@ -674,7 +677,7 @@
      * @see View#setScaleX(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator scaleX(float value) {
+    public @NonNull ViewPropertyAnimator scaleX(float value) {
         animateProperty(SCALE_X, value);
         return this;
     }
@@ -687,7 +690,7 @@
      * @see View#setScaleX(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator scaleXBy(float value) {
+    public @NonNull ViewPropertyAnimator scaleXBy(float value) {
         animatePropertyBy(SCALE_X, value);
         return this;
     }
@@ -700,7 +703,7 @@
      * @see View#setScaleY(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator scaleY(float value) {
+    public @NonNull ViewPropertyAnimator scaleY(float value) {
         animateProperty(SCALE_Y, value);
         return this;
     }
@@ -713,7 +716,7 @@
      * @see View#setScaleY(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator scaleYBy(float value) {
+    public @NonNull ViewPropertyAnimator scaleYBy(float value) {
         animatePropertyBy(SCALE_Y, value);
         return this;
     }
@@ -726,7 +729,7 @@
      * @see View#setAlpha(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator alpha(@FloatRange(from = 0.0f, to = 1.0f) float value) {
+    public @NonNull ViewPropertyAnimator alpha(@FloatRange(from = 0.0f, to = 1.0f) float value) {
         animateProperty(ALPHA, value);
         return this;
     }
@@ -739,7 +742,7 @@
      * @see View#setAlpha(float)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator alphaBy(float value) {
+    public @NonNull ViewPropertyAnimator alphaBy(float value) {
         animatePropertyBy(ALPHA, value);
         return this;
     }
@@ -765,7 +768,7 @@
      * @see View#setLayerType(int, android.graphics.Paint)
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator withLayer() {
+    public @NonNull ViewPropertyAnimator withLayer() {
          mPendingSetupAction= new Runnable() {
             @Override
             public void run() {
@@ -803,7 +806,7 @@
      * @param runnable The action to run when the next animation starts.
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator withStartAction(Runnable runnable) {
+    public @NonNull ViewPropertyAnimator withStartAction(Runnable runnable) {
         mPendingOnStartAction = runnable;
         if (runnable != null && mAnimatorOnStartMap == null) {
             mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
@@ -832,7 +835,7 @@
      * @param runnable The action to run when the next animation ends.
      * @return This object, allowing calls to methods in this class to be chained.
      */
-    public ViewPropertyAnimator withEndAction(Runnable runnable) {
+    public @NonNull ViewPropertyAnimator withEndAction(Runnable runnable) {
         mPendingOnEndAction = runnable;
         if (runnable != null && mAnimatorOnEndMap == null) {
             mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
@@ -1061,7 +1064,7 @@
     private class AnimatorEventListener
             implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
         @Override
-        public void onAnimationStart(Animator animation) {
+        public void onAnimationStart(@NonNull Animator animation) {
             if (mAnimatorSetupMap != null) {
                 Runnable r = mAnimatorSetupMap.get(animation);
                 if (r != null) {
@@ -1082,7 +1085,7 @@
         }
 
         @Override
-        public void onAnimationCancel(Animator animation) {
+        public void onAnimationCancel(@NonNull Animator animation) {
             if (mListener != null) {
                 mListener.onAnimationCancel(animation);
             }
@@ -1092,14 +1095,14 @@
         }
 
         @Override
-        public void onAnimationRepeat(Animator animation) {
+        public void onAnimationRepeat(@NonNull Animator animation) {
             if (mListener != null) {
                 mListener.onAnimationRepeat(animation);
             }
         }
 
         @Override
-        public void onAnimationEnd(Animator animation) {
+        public void onAnimationEnd(@NonNull Animator animation) {
             mView.setHasTransientState(false);
             if (mAnimatorCleanupMap != null) {
                 Runnable r = mAnimatorCleanupMap.get(animation);
@@ -1130,7 +1133,7 @@
          * the current value of each property.
          */
         @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
+        public void onAnimationUpdate(@NonNull ValueAnimator animation) {
             PropertyBundle propertyBundle = mAnimatorMap.get(animation);
             if (propertyBundle == null) {
                 // Shouldn't happen, but just to play it safe
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 386b277..777e89d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -236,7 +236,7 @@
 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
 public final class ViewRootImpl implements ViewParent,
         View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
-        AttachedSurfaceControl {
+        AttachedSurfaceControl, OnBackInvokedDispatcherOwner {
     private static final String TAG = "ViewRootImpl";
     private static final boolean DBG = false;
     private static final boolean LOCAL_LOGV = false;
@@ -313,10 +313,15 @@
     private @SurfaceControl.BufferTransform
             int mPreviousTransformHint = SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
     /**
-     * The fallback {@link OnBackInvokedDispatcher} when the window doesn't have a decor view.
+     * The top level {@link OnBackInvokedDispatcher}.
      */
-    private WindowOnBackInvokedDispatcher mFallbackOnBackInvokedDispatcher =
+    private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher =
             new WindowOnBackInvokedDispatcher();
+    /**
+     * Compatibility {@link OnBackInvokedCallback} that dispatches KEYCODE_BACK events
+     * to view root for apps using legacy back behavior.
+     */
+    private OnBackInvokedCallback mCompatOnBackInvokedCallback;
 
     /**
      * Callback for notifying about global configuration changes.
@@ -893,7 +898,6 @@
         mFastScrollSoundEffectsEnabled = audioManager.areNavigationRepeatSoundEffectsEnabled();
 
         mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
-        mFallbackOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow);
     }
 
     public static void addFirstDrawHandler(Runnable callback) {
@@ -1144,9 +1148,6 @@
                     if (pendingInsetsController != null) {
                         pendingInsetsController.replayAndAttach(mInsetsController);
                     }
-                    ((RootViewSurfaceTaker) mView)
-                            .provideWindowOnBackInvokedDispatcher()
-                            .attachToWindow(mWindowSession, mWindow);
                 }
 
                 try {
@@ -1193,6 +1194,15 @@
                         getAttachedWindowFrame(), 1f /* compactScale */,
                         mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
                 setFrame(mTmpFrames.frame);
+                registerBackCallbackOnWindow();
+                if (WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+                    // For apps requesting legacy back behavior, we add a compat callback that
+                    // dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
+                    // This way from system point of view, these apps are providing custom
+                    // {@link OnBackInvokedCallback}s, and will not play system back animations
+                    // for them.
+                    registerCompatOnBackInvokedCallback();
+                }
                 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                 if (res < WindowManagerGlobal.ADD_OKAY) {
                     mAttachInfo.mRootView = null;
@@ -1335,7 +1345,7 @@
     private void setTag() {
         final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
         if (split.length > 0) {
-            mTag = TAG + "[" + split[split.length - 1] + "]";
+            mTag =  "VRI[" + split[split.length - 1] + "]";
         }
     }
 
@@ -5934,7 +5944,7 @@
             }
         }
 
-        private boolean isBack(InputEvent event) {
+        boolean isBack(InputEvent event) {
             if (event instanceof KeyEvent) {
                 return ((KeyEvent) event).getKeyCode() == KeyEvent.KEYCODE_BACK;
             } else {
@@ -6474,6 +6484,19 @@
                 return FINISH_NOT_HANDLED;
             }
 
+            if (isBack(event)
+                    && mContext != null
+                    && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+                // Invoke the appropriate {@link OnBackInvokedCallback} if the new back
+                // navigation should be used, and the key event is not handled by anything else.
+                OnBackInvokedCallback topCallback =
+                        getOnBackInvokedDispatcher().getTopCallback();
+                if (topCallback != null) {
+                    topCallback.onBackInvoked();
+                    return FINISH_HANDLED;
+                }
+            }
+
             // This dispatch is for windows that don't have a Window.Callback. Otherwise,
             // the Window.Callback usually will have already called this (see
             // DecorView.superDispatchKeyEvent) leaving this call a no-op.
@@ -8417,6 +8440,8 @@
 
             mAdded = false;
         }
+        unregisterCompatOnBackInvokedCallback();
+        mOnBackInvokedDispatcher.detachFromWindow();
         WindowManagerGlobal.getInstance().doRemoveView(this);
     }
 
@@ -10771,12 +10796,49 @@
      * Returns the {@link OnBackInvokedDispatcher} on the decor view if one exists, or the
      * fallback {@link OnBackInvokedDispatcher} instance.
      */
-    @Nullable
-    public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
-        if (mView instanceof RootViewSurfaceTaker) {
-            return ((RootViewSurfaceTaker) mView).provideWindowOnBackInvokedDispatcher();
+    @NonNull
+    public WindowOnBackInvokedDispatcher getOnBackInvokedDispatcher() {
+        return mOnBackInvokedDispatcher;
+    }
+
+    /**
+     * When this ViewRootImpl is added to the window manager, transfers the first
+     * {@link OnBackInvokedCallback} to be called to the server.
+     */
+    private void registerBackCallbackOnWindow() {
+        mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow);
+    }
+
+    private void sendBackKeyEvent(int action) {
+        long when = SystemClock.uptimeMillis();
+        final KeyEvent ev = new KeyEvent(when, when, action,
+                KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
+                KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
+                KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
+                InputDevice.SOURCE_KEYBOARD);
+
+        ev.setDisplayId(mContext.getDisplay().getDisplayId());
+        if (mView != null) {
+            mView.dispatchKeyEvent(ev);
         }
-        return mFallbackOnBackInvokedDispatcher;
+    }
+
+    private void registerCompatOnBackInvokedCallback() {
+        mCompatOnBackInvokedCallback = new OnBackInvokedCallback() {
+            @Override
+            public void onBackInvoked() {
+                sendBackKeyEvent(KeyEvent.ACTION_DOWN);
+                sendBackKeyEvent(KeyEvent.ACTION_UP);
+            }
+        };
+        mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
+                mCompatOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+    }
+
+    private void unregisterCompatOnBackInvokedCallback() {
+        if (mCompatOnBackInvokedCallback != null) {
+            mOnBackInvokedDispatcher.unregisterOnBackInvokedCallback(mCompatOnBackInvokedCallback);
+        }
     }
 
     @Override
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index a427ab8..cd8dd86 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -553,8 +553,20 @@
     public static final int TYPE_ASSIST_READING_CONTEXT = 0x01000000;
 
     /**
-     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
-     * The type of change is not defined.
+     * Represents a change in the speech state defined by the content-change types. A change in the
+     * speech state occurs when another service is either speaking or listening for human speech.
+     * This event helps avoid conflicts where two services want to speak or one listens
+     * when another speaks.
+     * @see #SPEECH_STATE_SPEAKING_START
+     * @see #SPEECH_STATE_SPEAKING_END
+     * @see #SPEECH_STATE_LISTENING_START
+     * @see #SPEECH_STATE_LISTENING_END
+     */
+    public static final int TYPE_SPEECH_STATE_CHANGE = 0x02000000;
+
+    /**
+     * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: The type of change is not
+     * defined.
      */
     public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000000;
 
@@ -641,6 +653,27 @@
      */
     public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 0x0000200;
 
+    /** Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is speaking. */
+    public static final int SPEECH_STATE_SPEAKING_START = 0x00000001;
+
+    /**
+     * Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is no longer
+     * speaking.
+     */
+    public static final int SPEECH_STATE_SPEAKING_END = 0x00000002;
+
+    /**
+     * Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is listening to the
+     * microphone.
+     */
+    public static final int SPEECH_STATE_LISTENING_START = 0x00000004;
+
+    /**
+     * Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is no longer
+     * listening to the microphone.
+     */
+    public static final int SPEECH_STATE_LISTENING_END = 0x00000008;
+
     /**
      * Change type for {@link #TYPE_WINDOWS_CHANGED} event:
      * The window was added.
@@ -730,50 +763,69 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true, prefix = { "CONTENT_CHANGE_TYPE_" },
+    @IntDef(
+            flag = true,
+            prefix = {"CONTENT_CHANGE_TYPE_"},
             value = {
-                    CONTENT_CHANGE_TYPE_UNDEFINED,
-                    CONTENT_CHANGE_TYPE_SUBTREE,
-                    CONTENT_CHANGE_TYPE_TEXT,
-                    CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION,
-                    CONTENT_CHANGE_TYPE_STATE_DESCRIPTION,
-                    CONTENT_CHANGE_TYPE_PANE_TITLE,
-                    CONTENT_CHANGE_TYPE_PANE_APPEARED,
-                    CONTENT_CHANGE_TYPE_PANE_DISAPPEARED,
-                    CONTENT_CHANGE_TYPE_DRAG_STARTED,
-                    CONTENT_CHANGE_TYPE_DRAG_DROPPED,
-                    CONTENT_CHANGE_TYPE_DRAG_CANCELLED
+                CONTENT_CHANGE_TYPE_UNDEFINED,
+                CONTENT_CHANGE_TYPE_SUBTREE,
+                CONTENT_CHANGE_TYPE_TEXT,
+                CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION,
+                CONTENT_CHANGE_TYPE_STATE_DESCRIPTION,
+                CONTENT_CHANGE_TYPE_PANE_TITLE,
+                CONTENT_CHANGE_TYPE_PANE_APPEARED,
+                CONTENT_CHANGE_TYPE_PANE_DISAPPEARED,
+                CONTENT_CHANGE_TYPE_DRAG_STARTED,
+                CONTENT_CHANGE_TYPE_DRAG_DROPPED,
+                CONTENT_CHANGE_TYPE_DRAG_CANCELLED,
             })
     public @interface ContentChangeTypes {}
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "TYPE_" }, value = {
-            TYPE_VIEW_CLICKED,
-            TYPE_VIEW_LONG_CLICKED,
-            TYPE_VIEW_SELECTED,
-            TYPE_VIEW_FOCUSED,
-            TYPE_VIEW_TEXT_CHANGED,
-            TYPE_WINDOW_STATE_CHANGED,
-            TYPE_NOTIFICATION_STATE_CHANGED,
-            TYPE_VIEW_HOVER_ENTER,
-            TYPE_VIEW_HOVER_EXIT,
-            TYPE_TOUCH_EXPLORATION_GESTURE_START,
-            TYPE_TOUCH_EXPLORATION_GESTURE_END,
-            TYPE_WINDOW_CONTENT_CHANGED,
-            TYPE_VIEW_SCROLLED,
-            TYPE_VIEW_TEXT_SELECTION_CHANGED,
-            TYPE_ANNOUNCEMENT,
-            TYPE_VIEW_ACCESSIBILITY_FOCUSED,
-            TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
-            TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
-            TYPE_GESTURE_DETECTION_START,
-            TYPE_GESTURE_DETECTION_END,
-            TYPE_TOUCH_INTERACTION_START,
-            TYPE_TOUCH_INTERACTION_END,
-            TYPE_WINDOWS_CHANGED,
-            TYPE_VIEW_CONTEXT_CLICKED,
-            TYPE_ASSIST_READING_CONTEXT
-    })
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            flag = true,
+            prefix = {"SPEECH_STATE_"},
+            value = {
+                SPEECH_STATE_SPEAKING_START,
+                SPEECH_STATE_SPEAKING_END,
+                SPEECH_STATE_LISTENING_START,
+                SPEECH_STATE_LISTENING_END
+            })
+    public @interface SpeechStateChangeTypes {}
+
+    /** @hide */
+    @IntDef(
+            flag = true,
+            prefix = {"TYPE_"},
+            value = {
+                TYPE_VIEW_CLICKED,
+                TYPE_VIEW_LONG_CLICKED,
+                TYPE_VIEW_SELECTED,
+                TYPE_VIEW_FOCUSED,
+                TYPE_VIEW_TEXT_CHANGED,
+                TYPE_WINDOW_STATE_CHANGED,
+                TYPE_NOTIFICATION_STATE_CHANGED,
+                TYPE_VIEW_HOVER_ENTER,
+                TYPE_VIEW_HOVER_EXIT,
+                TYPE_TOUCH_EXPLORATION_GESTURE_START,
+                TYPE_TOUCH_EXPLORATION_GESTURE_END,
+                TYPE_WINDOW_CONTENT_CHANGED,
+                TYPE_VIEW_SCROLLED,
+                TYPE_VIEW_TEXT_SELECTION_CHANGED,
+                TYPE_ANNOUNCEMENT,
+                TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
+                TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
+                TYPE_GESTURE_DETECTION_START,
+                TYPE_GESTURE_DETECTION_END,
+                TYPE_TOUCH_INTERACTION_START,
+                TYPE_TOUCH_INTERACTION_END,
+                TYPE_WINDOWS_CHANGED,
+                TYPE_VIEW_CONTEXT_CLICKED,
+                TYPE_ASSIST_READING_CONTEXT,
+                TYPE_SPEECH_STATE_CHANGE
+            })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType {}
 
@@ -814,6 +866,7 @@
     int mAction;
     int mContentChangeTypes;
     int mWindowChangeTypes;
+    int mSpeechStateChangeTypes;
 
     /**
      * The stack trace describing where this event originated from on the app side.
@@ -867,6 +920,7 @@
         mMovementGranularity = event.mMovementGranularity;
         mAction = event.mAction;
         mContentChangeTypes = event.mContentChangeTypes;
+        mSpeechStateChangeTypes = event.mSpeechStateChangeTypes;
         mWindowChangeTypes = event.mWindowChangeTypes;
         mEventTime = event.mEventTime;
         mPackageName = event.mPackageName;
@@ -1008,6 +1062,51 @@
     }
 
     /**
+     * Gets the speech state signaled by a {@link #TYPE_SPEECH_STATE_CHANGE} event
+     *
+     * @see #SPEECH_STATE_SPEAKING_START
+     * @see #SPEECH_STATE_SPEAKING_END
+     * @see #SPEECH_STATE_LISTENING_START
+     * @see #SPEECH_STATE_LISTENING_END
+     */
+    public int getSpeechStateChangeTypes() {
+        return mSpeechStateChangeTypes;
+    }
+
+    private static String speechStateChangedTypesToString(int types) {
+        return BitUtils.flagsToString(
+                types, AccessibilityEvent::singleSpeechStateChangeTypeToString);
+    }
+
+    private static String singleSpeechStateChangeTypeToString(int type) {
+        switch (type) {
+            case SPEECH_STATE_SPEAKING_START:
+                return "SPEECH_STATE_SPEAKING_START";
+            case SPEECH_STATE_LISTENING_START:
+                return "SPEECH_STATE_LISTENING_START";
+            case SPEECH_STATE_SPEAKING_END:
+                return "SPEECH_STATE_SPEAKING_END";
+            case SPEECH_STATE_LISTENING_END:
+                return "SPEECH_STATE_LISTENING_END";
+            default:
+                return Integer.toHexString(type);
+        }
+    }
+
+    /**
+     * Sets the speech state type signaled by a {@link #TYPE_SPEECH_STATE_CHANGE} event
+     *
+     * @see #SPEECH_STATE_SPEAKING_START
+     * @see #SPEECH_STATE_SPEAKING_END
+     * @see #SPEECH_STATE_LISTENING_START
+     * @see #SPEECH_STATE_LISTENING_END
+     */
+    public void setSpeechStateChangeTypes(int state) {
+        enforceNotSealed();
+        mSpeechStateChangeTypes = state;
+    }
+
+    /**
      * Get the bit mask of change types signaled by a {@link #TYPE_WINDOWS_CHANGED} event. A
      * single event may represent multiple change types.
      *
@@ -1239,6 +1338,7 @@
         mAction = 0;
         mContentChangeTypes = 0;
         mWindowChangeTypes = 0;
+        mSpeechStateChangeTypes = 0;
         mPackageName = null;
         mEventTime = 0;
         if (mRecords != null) {
@@ -1261,6 +1361,7 @@
         mAction = parcel.readInt();
         mContentChangeTypes = parcel.readInt();
         mWindowChangeTypes = parcel.readInt();
+        mSpeechStateChangeTypes = parcel.readInt();
         mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
         mEventTime = parcel.readLong();
         mConnectionId = parcel.readInt();
@@ -1332,6 +1433,7 @@
         parcel.writeInt(mAction);
         parcel.writeInt(mContentChangeTypes);
         parcel.writeInt(mWindowChangeTypes);
+        parcel.writeInt(mSpeechStateChangeTypes);
         TextUtils.writeToParcel(mPackageName, parcel, 0);
         parcel.writeLong(mEventTime);
         parcel.writeInt(mConnectionId);
@@ -1500,6 +1602,7 @@
             case TYPE_WINDOWS_CHANGED: return "TYPE_WINDOWS_CHANGED";
             case TYPE_VIEW_CONTEXT_CLICKED: return "TYPE_VIEW_CONTEXT_CLICKED";
             case TYPE_ASSIST_READING_CONTEXT: return "TYPE_ASSIST_READING_CONTEXT";
+            case TYPE_SPEECH_STATE_CHANGE: return "TYPE_SPEECH_STATE_CHANGE";
             default: return Integer.toHexString(eventType);
         }
     }
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 6f4bc71..82e823f 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -526,9 +526,9 @@
      * @param prefetchFlags flags to guide prefetching.
      * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
      */
-    public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId,
-            int accessibilityWindowId, long accessibilityNodeId, boolean bypassCache,
-            int prefetchFlags, Bundle arguments) {
+    public @Nullable AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
+            int connectionId, int accessibilityWindowId, long accessibilityNodeId,
+            boolean bypassCache, int prefetchFlags, Bundle arguments) {
         if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS) != 0
                 && (prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) == 0) {
             throw new IllegalArgumentException("FLAG_PREFETCH_SIBLINGS"
diff --git a/core/java/android/view/accessibility/AccessibilityNodeProvider.java b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
index f4c7b96..91d4a35 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeProvider.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
@@ -17,6 +17,7 @@
 package android.view.accessibility;
 
 import android.accessibilityservice.AccessibilityService;
+import android.annotation.Nullable;
 import android.os.Bundle;
 import android.view.View;
 
@@ -195,7 +196,7 @@
      * @see View#createAccessibilityNodeInfo()
      * @see AccessibilityNodeInfo
      */
-    public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
+    public @Nullable AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) {
         return null;
     }
 
@@ -234,7 +235,7 @@
      * @see #createAccessibilityNodeInfo(int)
      * @see AccessibilityNodeInfo
      */
-    public boolean performAction(int virtualViewId, int action, Bundle arguments) {
+    public boolean performAction(int virtualViewId, int action, @Nullable Bundle arguments) {
         return false;
     }
 
@@ -252,7 +253,7 @@
      * @see #createAccessibilityNodeInfo(int)
      * @see AccessibilityNodeInfo
      */
-    public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text,
+    public @Nullable List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text,
             int virtualViewId) {
         return null;
     }
@@ -268,7 +269,7 @@
      * @see AccessibilityNodeInfo#FOCUS_INPUT
      * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
      */
-    public AccessibilityNodeInfo findFocus(int focus) {
+    public @Nullable AccessibilityNodeInfo findFocus(int focus) {
         return null;
     }
 }
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 426a3f4..cf2ea15 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -133,7 +133,7 @@
      *
      * @throws IllegalStateException If called from an AccessibilityService.
      */
-    public void setSource(View source) {
+    public void setSource(@Nullable View source) {
         setSource(source, AccessibilityNodeProvider.HOST_VIEW_ID);
     }
 
@@ -184,7 +184,7 @@
      * </p>
      * @return The info of the source.
      */
-    public AccessibilityNodeInfo getSource() {
+    public @Nullable AccessibilityNodeInfo getSource() {
         enforceSealed();
         if ((mConnectionId == UNDEFINED)
                 || (mSourceWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
@@ -629,7 +629,7 @@
      *
      * @return The class name.
      */
-    public CharSequence getClassName() {
+    public @Nullable CharSequence getClassName() {
         return mClassName;
     }
 
@@ -640,7 +640,7 @@
      *
      * @throws IllegalStateException If called from an AccessibilityService.
      */
-    public void setClassName(CharSequence className) {
+    public void setClassName(@Nullable CharSequence className) {
         enforceNotSealed();
         mClassName = className;
     }
@@ -651,7 +651,7 @@
      *
      * @return The text.
      */
-    public List<CharSequence> getText() {
+    public @NonNull List<CharSequence> getText() {
         return mText;
     }
 
@@ -660,7 +660,7 @@
      *
      * @return The text before the change.
      */
-    public CharSequence getBeforeText() {
+    public @Nullable CharSequence getBeforeText() {
         return mBeforeText;
     }
 
@@ -671,7 +671,7 @@
      *
      * @throws IllegalStateException If called from an AccessibilityService.
      */
-    public void setBeforeText(CharSequence beforeText) {
+    public void setBeforeText(@Nullable CharSequence beforeText) {
         enforceNotSealed();
         mBeforeText = (beforeText == null) ? null
                 : beforeText.subSequence(0, beforeText.length());
@@ -682,7 +682,7 @@
      *
      * @return The description.
      */
-    public CharSequence getContentDescription() {
+    public @Nullable CharSequence getContentDescription() {
         return mContentDescription;
     }
 
@@ -693,7 +693,7 @@
      *
      * @throws IllegalStateException If called from an AccessibilityService.
      */
-    public void setContentDescription(CharSequence contentDescription) {
+    public void setContentDescription(@Nullable CharSequence contentDescription) {
         enforceNotSealed();
         mContentDescription = (contentDescription == null) ? null
                 : contentDescription.subSequence(0, contentDescription.length());
@@ -704,7 +704,7 @@
      *
      * @return The parcelable data.
      */
-    public Parcelable getParcelableData() {
+    public @Nullable Parcelable getParcelableData() {
         return mParcelableData;
     }
 
@@ -715,7 +715,7 @@
      *
      * @throws IllegalStateException If called from an AccessibilityService.
      */
-    public void setParcelableData(Parcelable parcelableData) {
+    public void setParcelableData(@Nullable Parcelable parcelableData) {
         enforceNotSealed();
         mParcelableData = parcelableData;
     }
@@ -822,7 +822,7 @@
      * @return An instance.
      */
     @Deprecated
-    public static AccessibilityRecord obtain(AccessibilityRecord record) {
+    public static @NonNull AccessibilityRecord obtain(@NonNull AccessibilityRecord record) {
        AccessibilityRecord clone = AccessibilityRecord.obtain();
        clone.init(record);
        return clone;
@@ -836,7 +836,7 @@
      * @return An instance.
      */
     @Deprecated
-    public static AccessibilityRecord obtain() {
+    public static @NonNull AccessibilityRecord obtain() {
         return new AccessibilityRecord();
     }
 
@@ -854,7 +854,7 @@
      *
      * @param record The to initialize from.
      */
-    void init(AccessibilityRecord record) {
+    void init(@NonNull AccessibilityRecord record) {
         mSealed = record.mSealed;
         mBooleanProperties = record.mBooleanProperties;
         mCurrentItemIndex = record.mCurrentItemIndex;
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 3914a3c..fadbdbb 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -1251,18 +1251,19 @@
         public float value;
 
         /**
-         * Size descriptions can appear inthree forms:
+         * Size descriptions can appear in four forms:
          * <ol>
          * <li>An absolute size. This is represented by a number.</li>
          * <li>A size relative to the size of the object being animated. This
-         * is represented by a number followed by "%".</li> *
+         * is represented by a number followed by "%".</li>
          * <li>A size relative to the size of the parent of object being
          * animated. This is represented by a number followed by "%p".</li>
+         * <li>(Starting from API 32) A complex number.</li>
          * </ol>
          * @param value The typed value to parse
          * @return The parsed version of the description
          */
-        static Description parseValue(TypedValue value) {
+        static Description parseValue(TypedValue value, Context context) {
             Description d = new Description();
             if (value == null) {
                 d.type = ABSOLUTE;
@@ -1283,6 +1284,11 @@
                     d.type = ABSOLUTE;
                     d.value = value.data;
                     return d;
+                } else if (value.type == TypedValue.TYPE_DIMENSION) {
+                    d.type = ABSOLUTE;
+                    d.value = TypedValue.complexToDimension(value.data,
+                            context.getResources().getDisplayMetrics());
+                    return d;
                 }
             }
 
diff --git a/core/java/android/view/animation/ClipRectAnimation.java b/core/java/android/view/animation/ClipRectAnimation.java
index 21509d3..3f4b3e7 100644
--- a/core/java/android/view/animation/ClipRectAnimation.java
+++ b/core/java/android/view/animation/ClipRectAnimation.java
@@ -20,7 +20,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 
 /**
  * An animation that controls the clip of an object. See the
@@ -66,43 +65,43 @@
                 com.android.internal.R.styleable.ClipRectAnimation);
 
         Description d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_fromLeft));
+                com.android.internal.R.styleable.ClipRectAnimation_fromLeft), context);
         mFromLeftType = d.type;
         mFromLeftValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_fromTop));
+                com.android.internal.R.styleable.ClipRectAnimation_fromTop), context);
         mFromTopType = d.type;
         mFromTopValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_fromRight));
+                com.android.internal.R.styleable.ClipRectAnimation_fromRight), context);
         mFromRightType = d.type;
         mFromRightValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_fromBottom));
+                com.android.internal.R.styleable.ClipRectAnimation_fromBottom), context);
         mFromBottomType = d.type;
         mFromBottomValue = d.value;
 
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_toLeft));
+                com.android.internal.R.styleable.ClipRectAnimation_toLeft), context);
         mToLeftType = d.type;
         mToLeftValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_toTop));
+                com.android.internal.R.styleable.ClipRectAnimation_toTop), context);
         mToTopType = d.type;
         mToTopValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_toRight));
+                com.android.internal.R.styleable.ClipRectAnimation_toRight), context);
         mToRightType = d.type;
         mToRightValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ClipRectAnimation_toBottom));
+                com.android.internal.R.styleable.ClipRectAnimation_toBottom), context);
         mToBottomType = d.type;
         mToBottomValue = d.value;
 
diff --git a/core/java/android/view/animation/ExtendAnimation.java b/core/java/android/view/animation/ExtendAnimation.java
index fd627e5..210eb8a 100644
--- a/core/java/android/view/animation/ExtendAnimation.java
+++ b/core/java/android/view/animation/ExtendAnimation.java
@@ -63,43 +63,43 @@
                 com.android.internal.R.styleable.ExtendAnimation);
 
         Description d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_fromExtendLeft));
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendLeft), context);
         mFromLeftType = d.type;
         mFromLeftValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_fromExtendTop));
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendTop), context);
         mFromTopType = d.type;
         mFromTopValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_fromExtendRight));
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendRight), context);
         mFromRightType = d.type;
         mFromRightValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_fromExtendBottom));
+                com.android.internal.R.styleable.ExtendAnimation_fromExtendBottom), context);
         mFromBottomType = d.type;
         mFromBottomValue = d.value;
 
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_toExtendLeft));
+                com.android.internal.R.styleable.ExtendAnimation_toExtendLeft), context);
         mToLeftType = d.type;
         mToLeftValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_toExtendTop));
+                com.android.internal.R.styleable.ExtendAnimation_toExtendTop), context);
         mToTopType = d.type;
         mToTopValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_toExtendRight));
+                com.android.internal.R.styleable.ExtendAnimation_toExtendRight), context);
         mToRightType = d.type;
         mToRightValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ExtendAnimation_toExtendBottom));
+                com.android.internal.R.styleable.ExtendAnimation_toExtendBottom), context);
         mToBottomType = d.type;
         mToBottomValue = d.value;
 
diff --git a/core/java/android/view/animation/GridLayoutAnimationController.java b/core/java/android/view/animation/GridLayoutAnimationController.java
index 0f189ae..c77f54f 100644
--- a/core/java/android/view/animation/GridLayoutAnimationController.java
+++ b/core/java/android/view/animation/GridLayoutAnimationController.java
@@ -116,10 +116,12 @@
                 com.android.internal.R.styleable.GridLayoutAnimation);
 
         Animation.Description d = Animation.Description.parseValue(
-                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_columnDelay));
+                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_columnDelay),
+                context);
         mColumnDelay = d.value;
         d = Animation.Description.parseValue(
-                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_rowDelay));
+                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_rowDelay),
+                context);
         mRowDelay = d.value;
         //noinspection PointlessBitwiseExpression
         mDirection = a.getInt(com.android.internal.R.styleable.GridLayoutAnimation_direction,
diff --git a/core/java/android/view/animation/LayoutAnimationController.java b/core/java/android/view/animation/LayoutAnimationController.java
index e2b7519..1d56d29 100644
--- a/core/java/android/view/animation/LayoutAnimationController.java
+++ b/core/java/android/view/animation/LayoutAnimationController.java
@@ -106,7 +106,7 @@
         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LayoutAnimation);
 
         Animation.Description d = Animation.Description.parseValue(
-                a.peekValue(com.android.internal.R.styleable.LayoutAnimation_delay));
+                a.peekValue(com.android.internal.R.styleable.LayoutAnimation_delay), context);
         mDelay = d.value;
 
         mOrder = a.getInt(com.android.internal.R.styleable.LayoutAnimation_animationOrder, ORDER_NORMAL);
diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java
index 99d6b9c..341c71b 100644
--- a/core/java/android/view/animation/PathInterpolator.java
+++ b/core/java/android/view/animation/PathInterpolator.java
@@ -15,6 +15,8 @@
  */
 package android.view.animation;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -61,7 +63,7 @@
      *
      * @param path The <code>Path</code> to use to make the line representing the interpolator.
      */
-    public PathInterpolator(Path path) {
+    public PathInterpolator(@NonNull Path path) {
         initPath(path);
     }
 
@@ -94,7 +96,7 @@
     }
 
     /** @hide */
-    public PathInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+    public PathInterpolator(Resources res, @Nullable Theme theme, @NonNull AttributeSet attrs) {
         TypedArray a;
         if (theme != null) {
             a = theme.obtainStyledAttributes(attrs, R.styleable.PathInterpolator, 0, 0);
diff --git a/core/java/android/view/animation/RotateAnimation.java b/core/java/android/view/animation/RotateAnimation.java
index 3c325d9..0613cd2 100644
--- a/core/java/android/view/animation/RotateAnimation.java
+++ b/core/java/android/view/animation/RotateAnimation.java
@@ -56,12 +56,12 @@
         mToDegrees = a.getFloat(com.android.internal.R.styleable.RotateAnimation_toDegrees, 0.0f);
 
         Description d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.RotateAnimation_pivotX));
+                com.android.internal.R.styleable.RotateAnimation_pivotX), context);
         mPivotXType = d.type;
         mPivotXValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.RotateAnimation_pivotY));
+                com.android.internal.R.styleable.RotateAnimation_pivotY), context);
         mPivotYType = d.type;
         mPivotYValue = d.value;
 
diff --git a/core/java/android/view/animation/ScaleAnimation.java b/core/java/android/view/animation/ScaleAnimation.java
index e9a8436..533ef45 100644
--- a/core/java/android/view/animation/ScaleAnimation.java
+++ b/core/java/android/view/animation/ScaleAnimation.java
@@ -118,12 +118,12 @@
         }
 
         Description d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.ScaleAnimation_pivotX));
+                com.android.internal.R.styleable.ScaleAnimation_pivotX), context);
         mPivotXType = d.type;
         mPivotXValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.ScaleAnimation_pivotY));
+                com.android.internal.R.styleable.ScaleAnimation_pivotY), context);
         mPivotYType = d.type;
         mPivotYValue = d.value;
 
diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java
index 3365c70..e27469c 100644
--- a/core/java/android/view/animation/TranslateAnimation.java
+++ b/core/java/android/view/animation/TranslateAnimation.java
@@ -73,22 +73,22 @@
                 com.android.internal.R.styleable.TranslateAnimation);
 
         Description d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.TranslateAnimation_fromXDelta));
+                com.android.internal.R.styleable.TranslateAnimation_fromXDelta), context);
         mFromXType = d.type;
         mFromXValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-                com.android.internal.R.styleable.TranslateAnimation_toXDelta));
+                com.android.internal.R.styleable.TranslateAnimation_toXDelta), context);
         mToXType = d.type;
         mToXValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.TranslateAnimation_fromYDelta));
+                com.android.internal.R.styleable.TranslateAnimation_fromYDelta), context);
         mFromYType = d.type;
         mFromYValue = d.value;
 
         d = Description.parseValue(a.peekValue(
-            com.android.internal.R.styleable.TranslateAnimation_toYDelta));
+                com.android.internal.R.styleable.TranslateAnimation_toYDelta), context);
         mToYType = d.type;
         mToYValue = d.value;
 
diff --git a/core/java/android/view/autofill/AutofillClientController.java b/core/java/android/view/autofill/AutofillClientController.java
index c47f6f7..0f0fa4a 100644
--- a/core/java/android/view/autofill/AutofillClientController.java
+++ b/core/java/android/view/autofill/AutofillClientController.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.text.TextUtils;
+import android.util.Dumpable;
 import android.util.Log;
 import android.util.Slog;
 import android.view.KeyEvent;
@@ -43,7 +44,7 @@
  *
  * @hide
  */
-public final class AutofillClientController implements AutofillManager.AutofillClient {
+public final class AutofillClientController implements AutofillManager.AutofillClient, Dumpable {
 
     private static final String TAG = "AutofillClientController";
 
@@ -54,6 +55,8 @@
     public static final String AUTOFILL_RESET_NEEDED = "@android:autofillResetNeeded";
     public static final String AUTO_FILL_AUTH_WHO_PREFIX = "@android:autoFillAuth:";
 
+    public static final String DUMPABLE_NAME = "AutofillManager";
+
     /** The last autofill id that was returned from {@link #getNextAutofillId()} */
     public int mLastAutofillId = View.LAST_APP_AUTOFILL_ID;
 
@@ -73,6 +76,7 @@
      */
     public AutofillClientController(Activity activity) {
         mActivity = activity;
+        activity.addDumpable(this);
     }
 
     private AutofillManager getAutofillManager() {
@@ -280,10 +284,14 @@
         }
     }
 
-    /**
-     * Prints autofill related information for the Activity.
-     */
-    public void dumpAutofillManager(String prefix, PrintWriter writer) {
+    @Override
+    public String getDumpableName() {
+        return DUMPABLE_NAME;
+    }
+
+    @Override
+    public void dump(PrintWriter writer, String[] args) {
+        final String prefix = "";
         final AutofillManager afm = getAutofillManager();
         if (afm != null) {
             afm.dump(prefix, writer);
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index bcab366..54bd9e7 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -29,6 +29,7 @@
 import android.annotation.TestApi;
 import android.annotation.UiThread;
 import android.annotation.UserIdInt;
+import android.app.Activity;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
@@ -41,6 +42,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.util.Dumpable;
 import android.util.Log;
 import android.util.Slog;
 import android.view.View;
@@ -215,6 +217,9 @@
     /** @hide */
     public static final boolean DEBUG = false;
 
+    /** @hide */
+    public static final String DUMPABLE_NAME = "ContentCaptureManager";
+
     /** Error happened during the data sharing session. */
     public static final int DATA_SHARE_ERROR_UNKNOWN = 1;
 
@@ -402,6 +407,9 @@
         mService = Objects.requireNonNull(service, "service cannot be null");
         mOptions = Objects.requireNonNull(options, "options cannot be null");
 
+        if (context instanceof Activity) {
+            ((Activity) context).addDumpable(new Dumper());
+        }
         ContentCaptureHelper.setLoggingLevel(mOptions.loggingLevel);
 
         if (sVerbose) Log.v(TAG, "Constructor for " + context.getPackageName());
@@ -740,28 +748,37 @@
         return resultReceiver;
     }
 
-    /** @hide */
-    public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.println("ContentCaptureManager");
-        final String prefix2 = prefix + "  ";
-        synchronized (mLock) {
-            pw.print(prefix2); pw.print("isContentCaptureEnabled(): ");
-            pw.println(isContentCaptureEnabled());
-            pw.print(prefix2); pw.print("Debug: "); pw.print(sDebug);
-            pw.print(" Verbose: "); pw.println(sVerbose);
-            pw.print(prefix2); pw.print("Context: "); pw.println(mContext);
-            pw.print(prefix2); pw.print("User: "); pw.println(mContext.getUserId());
-            pw.print(prefix2); pw.print("Service: "); pw.println(mService);
-            pw.print(prefix2); pw.print("Flags: "); pw.println(mFlags);
-            pw.print(prefix2); pw.print("Options: "); mOptions.dumpShort(pw); pw.println();
-            if (mMainSession != null) {
-                final String prefix3 = prefix2 + "  ";
-                pw.print(prefix2); pw.println("Main session:");
-                mMainSession.dump(prefix3, pw);
-            } else {
-                pw.print(prefix2); pw.println("No sessions");
+    // NOTE: ContentCaptureManager cannot implement it directly as it would be exposed as public API
+    private final class Dumper implements Dumpable {
+        @Override
+        public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
+            String prefix = "";
+            pw.print(prefix); pw.println("ContentCaptureManager");
+            final String prefix2 = prefix + "  ";
+            synchronized (mLock) {
+                pw.print(prefix2); pw.print("isContentCaptureEnabled(): ");
+                pw.println(isContentCaptureEnabled());
+                pw.print(prefix2); pw.print("Debug: "); pw.print(sDebug);
+                pw.print(" Verbose: "); pw.println(sVerbose);
+                pw.print(prefix2); pw.print("Context: "); pw.println(mContext);
+                pw.print(prefix2); pw.print("User: "); pw.println(mContext.getUserId());
+                pw.print(prefix2); pw.print("Service: "); pw.println(mService);
+                pw.print(prefix2); pw.print("Flags: "); pw.println(mFlags);
+                pw.print(prefix2); pw.print("Options: "); mOptions.dumpShort(pw); pw.println();
+                if (mMainSession != null) {
+                    final String prefix3 = prefix2 + "  ";
+                    pw.print(prefix2); pw.println("Main session:");
+                    mMainSession.dump(prefix3, pw);
+                } else {
+                    pw.print(prefix2); pw.println("No sessions");
+                }
             }
         }
+
+        @Override
+        public String getDumpableName() {
+            return DUMPABLE_NAME;
+        }
     }
 
     /**
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index 2702c2d..8cf032b 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -33,6 +33,7 @@
 import android.os.Process;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Dumpable;
 import android.util.IntArray;
 import android.util.Log;
 import android.util.LongSparseArray;
@@ -62,11 +63,15 @@
  *
  * @hide
  */
-public class UiTranslationController {
+public class UiTranslationController implements Dumpable {
 
     public static final boolean DEBUG = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG);
 
+    /** @hide */
+    public static final String DUMPABLE_NAME = "UiTranslationController";
+
     private static final String TAG = "UiTranslationController";
+
     @NonNull
     private final Activity mActivity;
     @NonNull
@@ -104,6 +109,7 @@
                         Process.THREAD_PRIORITY_FOREGROUND);
         mWorkerThread.start();
         mWorkerHandler = mWorkerThread.getThreadHandler();
+        activity.addDumpable(this);
     }
 
     /**
@@ -206,10 +212,14 @@
         mLastRequestAutofillIds.addAll(views);
     }
 
-    /**
-     * Called to dump the translation information for Activity.
-     */
-    public void dump(String outerPrefix, PrintWriter pw) {
+    @Override
+    public String getDumpableName() {
+        return DUMPABLE_NAME;
+    }
+
+    @Override
+    public void dump(PrintWriter pw, String[] args) {
+        String outerPrefix = "";
         pw.print(outerPrefix); pw.println("UiTranslationController:");
         final String pfx = outerPrefix + "  ";
         pw.print(pfx); pw.print("activity: "); pw.print(mActivity);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0fe2ed5..9efa583 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10821,8 +10821,11 @@
                         && mSavedMarqueeModeLayout.getLineWidth(0) > width));
     }
 
+    /**
+     * @hide
+     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    private void startMarquee() {
+    protected void startMarquee() {
         // Do not ellipsize EditText
         if (getKeyListener() != null) return;
 
@@ -10848,7 +10851,10 @@
         }
     }
 
-    private void stopMarquee() {
+    /**
+     * @hide
+     */
+    protected void stopMarquee() {
         if (mMarquee != null && !mMarquee.isStopped()) {
             mMarquee.stop();
         }
diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java
index 571714c..18c20e2 100644
--- a/core/java/android/window/BackNavigationInfo.java
+++ b/core/java/android/window/BackNavigationInfo.java
@@ -16,8 +16,6 @@
 
 package android.window;
 
-import static java.util.Objects.requireNonNull;
-
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -61,6 +59,12 @@
     public static final int TYPE_CROSS_TASK = 3;
 
     /**
+     * A {@link android.view.OnBackInvokedCallback} is available and needs to be called.
+     * <p>
+     */
+    public static final int TYPE_CALLBACK = 4;
+
+    /**
      * Defines the type of back destinations a back even can lead to. This is used to define the
      * type of animation that need to be run on SystemUI.
      */
@@ -84,35 +88,39 @@
     private final RemoteCallback mRemoteCallback;
     @Nullable
     private final WindowConfiguration mTaskWindowConfiguration;
+    @Nullable
+    private final IOnBackInvokedCallback mOnBackInvokedCallback;
 
     /**
      * Create a new {@link BackNavigationInfo} instance.
      *
-     * @param type  The {@link BackTargetType} of the destination (what will be displayed after
-     *              the back action)
-     * @param topWindowLeash      The leash to animate away the current topWindow. The consumer
-     *                            of the leash is responsible for removing it.
-     * @param screenshotSurface The screenshot of the previous activity to be displayed.
-     * @param screenshotBuffer      A buffer containing a screenshot used to display the activity.
-     *                            See {@link  #getScreenshotHardwareBuffer()} for information
-     *                            about nullity.
-     * @param taskWindowConfiguration The window configuration of the Task being animated
-     *                            beneath.
-     * @param onBackNavigationDone   The callback to be called once the client is done with the back
-     *                           preview.
+     * @param type                    The {@link BackTargetType} of the destination (what will be
+     *                                displayed after the back action).
+     * @param topWindowLeash          The leash to animate away the current topWindow. The consumer
+     *                                of the leash is responsible for removing it.
+     * @param screenshotSurface       The screenshot of the previous activity to be displayed.
+     * @param screenshotBuffer        A buffer containing a screenshot used to display the activity.
+     *                                See {@link  #getScreenshotHardwareBuffer()} for information
+     *                                about nullity.
+     * @param taskWindowConfiguration The window configuration of the Task being animated beneath.
+     * @param onBackNavigationDone    The callback to be called once the client is done with the
+     *                                back preview.
+     * @param onBackInvokedCallback   The back callback registered by the current top level window.
      */
     public BackNavigationInfo(@BackTargetType int type,
             @Nullable SurfaceControl topWindowLeash,
             @Nullable SurfaceControl screenshotSurface,
             @Nullable HardwareBuffer screenshotBuffer,
             @Nullable WindowConfiguration taskWindowConfiguration,
-            @NonNull RemoteCallback onBackNavigationDone) {
+            @Nullable RemoteCallback onBackNavigationDone,
+            @Nullable IOnBackInvokedCallback onBackInvokedCallback) {
         mType = type;
         mDepartingWindowContainer = topWindowLeash;
         mScreenshotSurface = screenshotSurface;
         mScreenshotBuffer = screenshotBuffer;
         mTaskWindowConfiguration = taskWindowConfiguration;
         mRemoteCallback = onBackNavigationDone;
+        mOnBackInvokedCallback = onBackInvokedCallback;
     }
 
     private BackNavigationInfo(@NonNull Parcel in) {
@@ -121,7 +129,8 @@
         mScreenshotSurface = in.readTypedObject(SurfaceControl.CREATOR);
         mScreenshotBuffer = in.readTypedObject(HardwareBuffer.CREATOR);
         mTaskWindowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
-        mRemoteCallback = requireNonNull(in.readTypedObject(RemoteCallback.CREATOR));
+        mRemoteCallback = in.readTypedObject(RemoteCallback.CREATOR);
+        mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder());
     }
 
     @Override
@@ -132,10 +141,12 @@
         dest.writeTypedObject(mScreenshotBuffer, flags);
         dest.writeTypedObject(mTaskWindowConfiguration, flags);
         dest.writeTypedObject(mRemoteCallback, flags);
+        dest.writeStrongInterface(mOnBackInvokedCallback);
     }
 
     /**
      * Returns the type of back navigation that is about to happen.
+     *
      * @see BackTargetType
      */
     public @BackTargetType int getType() {
@@ -152,8 +163,8 @@
     }
 
     /**
-     *  Returns the {@link SurfaceControl} that should be used to display a screenshot of the
-     *  previous activity.
+     * Returns the {@link SurfaceControl} that should be used to display a screenshot of the
+     * previous activity.
      */
     @Nullable
     public SurfaceControl getScreenshotSurface() {
@@ -185,11 +196,27 @@
     }
 
     /**
+     * Returns the {@link android.view.OnBackInvokedCallback} of the top level window or null if
+     * the client didn't register a callback.
+     * <p>
+     * This is never null when {@link #getType} returns {@link #TYPE_CALLBACK}.
+     *
+     * @see android.view.OnBackInvokedCallback
+     * @see android.view.OnBackInvokedDispatcher
+     */
+    @Nullable
+    public IOnBackInvokedCallback getOnBackInvokedCallback() {
+        return mOnBackInvokedCallback;
+    }
+
+    /**
      * Callback to be called when the back preview is finished in order to notify the server that
      * it can clean up the resources created for the animation.
      */
     public void onBackNavigationFinished() {
-        mRemoteCallback.sendResult(null);
+        if (mRemoteCallback != null) {
+            mRemoteCallback.sendResult(null);
+        }
     }
 
     @Override
@@ -218,6 +245,7 @@
                 + ", mTaskWindowConfiguration= " + mTaskWindowConfiguration
                 + ", mScreenshotBuffer=" + mScreenshotBuffer
                 + ", mRemoteCallback=" + mRemoteCallback
+                + ", mOnBackInvokedCallback=" + mOnBackInvokedCallback
                 + '}';
     }
 
@@ -226,7 +254,7 @@
      */
     public static String typeToString(@BackTargetType int type) {
         switch (type) {
-            case  TYPE_UNDEFINED:
+            case TYPE_UNDEFINED:
                 return "TYPE_UNDEFINED";
             case TYPE_DIALOG_CLOSE:
                 return "TYPE_DIALOG_CLOSE";
diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
new file mode 100644
index 0000000..4de977a
--- /dev/null
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022 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.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+import android.util.Pair;
+import android.view.OnBackInvokedCallback;
+import android.view.OnBackInvokedDispatcher;
+import android.view.OnBackInvokedDispatcherOwner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@link OnBackInvokedDispatcher} only used to hold callbacks while an actual
+ * dispatcher becomes available. <b>It does not dispatch the back events</b>.
+ * <p>
+ * Once the actual {@link OnBackInvokedDispatcherOwner} becomes available,
+ * {@link #setActualDispatcherOwner(OnBackInvokedDispatcherOwner)} needs to
+ * be called and this {@link ProxyOnBackInvokedDispatcher} will pass the callback registrations
+ * onto it.
+ * <p>
+ * This dispatcher will continue to keep track of callback registrations and when a dispatcher is
+ * removed or set it will unregister the callbacks from the old one and register them on the new
+ * one unless {@link #reset()} is called before.
+ *
+ * @hide
+ */
+public class ProxyOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
+
+    /**
+     * List of pair representing an {@link OnBackInvokedCallback} and its associated priority.
+     *
+     * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)
+     */
+    private final List<Pair<OnBackInvokedCallback, Integer>> mCallbacks = new ArrayList<>();
+    private final Object mLock = new Object();
+    private OnBackInvokedDispatcherOwner mActualDispatcherOwner = null;
+
+    @Override
+    public void registerOnBackInvokedCallback(
+            @NonNull OnBackInvokedCallback callback, int priority) {
+        if (DEBUG) {
+            Log.v(TAG, String.format("Pending register %s. Actual=%s", callback,
+                    mActualDispatcherOwner));
+        }
+        if (priority < 0) {
+            throw new IllegalArgumentException("Application registered OnBackInvokedCallback "
+                    + "cannot have negative priority. Priority: " + priority);
+        }
+        registerOnBackInvokedCallbackUnchecked(callback, priority);
+    }
+
+    @Override
+    public void registerSystemOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback) {
+        registerOnBackInvokedCallbackUnchecked(callback, PRIORITY_SYSTEM);
+    }
+
+    @Override
+    public void unregisterOnBackInvokedCallback(
+            @NonNull OnBackInvokedCallback callback) {
+        if (DEBUG) {
+            Log.v(TAG, String.format("Pending unregister %s. Actual=%s", callback,
+                    mActualDispatcherOwner));
+        }
+        synchronized (mLock) {
+            mCallbacks.removeIf((p) -> p.first.equals(callback));
+        }
+    }
+
+    private void registerOnBackInvokedCallbackUnchecked(
+            @NonNull OnBackInvokedCallback callback, int priority) {
+        synchronized (mLock) {
+            mCallbacks.add(Pair.create(callback, priority));
+            if (mActualDispatcherOwner != null) {
+                mActualDispatcherOwner.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+                        callback, priority);
+            }
+        }
+    }
+
+    /**
+     * Transfers all the pending callbacks to the provided dispatcher.
+     * <p>
+     * The callbacks are registered on the dispatcher in the same order as they were added on this
+     * proxy dispatcher.
+     */
+    private void transferCallbacksToDispatcher() {
+        if (mActualDispatcherOwner == null) {
+            return;
+        }
+        OnBackInvokedDispatcher dispatcher =
+                mActualDispatcherOwner.getOnBackInvokedDispatcher();
+        if (DEBUG) {
+            Log.v(TAG, String.format("Pending transferring %d callbacks to %s", mCallbacks.size(),
+                    dispatcher));
+        }
+        for (Pair<OnBackInvokedCallback, Integer> callbackPair : mCallbacks) {
+            int priority = callbackPair.second;
+            if (priority >= 0) {
+                dispatcher.registerOnBackInvokedCallback(callbackPair.first, priority);
+            } else {
+                dispatcher.registerSystemOnBackInvokedCallback(callbackPair.first);
+            }
+        }
+        mCallbacks.clear();
+    }
+
+    private void clearCallbacksOnDispatcher() {
+        if (mActualDispatcherOwner == null) {
+            return;
+        }
+        OnBackInvokedDispatcher onBackInvokedDispatcher =
+                mActualDispatcherOwner.getOnBackInvokedDispatcher();
+        for (Pair<OnBackInvokedCallback, Integer> callback : mCallbacks) {
+            onBackInvokedDispatcher.unregisterOnBackInvokedCallback(callback.first);
+        }
+    }
+
+    /**
+     * Resets this {@link ProxyOnBackInvokedDispatcher} so it loses track of the currently
+     * registered callbacks.
+     * <p>
+     * Using this method means that when setting a new {@link OnBackInvokedDispatcherOwner}, the
+     * callbacks registered on the old one won't be removed from it and won't be registered on
+     * the new one.
+     */
+    public void reset() {
+        if (DEBUG) {
+            Log.v(TAG, "Pending reset callbacks");
+        }
+        synchronized (mLock) {
+            mCallbacks.clear();
+        }
+    }
+
+    /**
+     * Sets the actual {@link OnBackInvokedDispatcherOwner} that will provides the
+     * {@link OnBackInvokedDispatcher} onto which the callbacks will be registered.
+     * <p>
+     * If any dispatcher owner was already present, all the callbacks that were added via this
+     * {@link ProxyOnBackInvokedDispatcher} will be unregistered from the old one and registered
+     * on the new one if it is not null.
+     * <p>
+     * If you do not wish for the previously registered callbacks to be reassigned to the new
+     * dispatcher, {@link #reset} must be called beforehand.
+     */
+    public void setActualDispatcherOwner(
+            @Nullable OnBackInvokedDispatcherOwner actualDispatcherOwner) {
+        if (DEBUG) {
+            Log.v(TAG, String.format("Pending setActual %s. Current %s",
+                            actualDispatcherOwner, mActualDispatcherOwner));
+        }
+        synchronized (mLock) {
+            if (actualDispatcherOwner == mActualDispatcherOwner) {
+                return;
+            }
+            clearCallbacksOnDispatcher();
+            mActualDispatcherOwner = actualDispatcherOwner;
+            transferCallbacksToDispatcher();
+        }
+    }
+}
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 2978604..d37d3b4 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -18,8 +18,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.compat.CompatChanges;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.view.IWindow;
 import android.view.IWindowSession;
@@ -31,7 +33,7 @@
 import java.util.TreeMap;
 
 /**
- * Provides window based implementation of {@link OnBackInvokedDispatcher}.
+ * Provides window based implementation of {@link android.view.OnBackInvokedDispatcher}.
  *
  * Callbacks with higher priorities receive back dispatching first.
  * Within the same priority, callbacks receive back dispatching in the reverse order
@@ -39,16 +41,19 @@
  *
  * When the top priority callback is updated, the new callback is propagated to the Window Manager
  * if the window the instance is associated with has been attached. It is allowed to register /
- * unregister {@link OnBackInvokedCallback}s before the window is attached, although callbacks
- * will not receive dispatches until window attachment.
+ * unregister {@link android.view.OnBackInvokedCallback}s before the window is attached, although
+ * callbacks will not receive dispatches until window attachment.
  *
  * @hide
  */
-public class WindowOnBackInvokedDispatcher extends OnBackInvokedDispatcher {
+public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
     private IWindowSession mWindowSession;
     private IWindow mWindow;
     private static final String TAG = "WindowOnBackDispatcher";
     private static final boolean DEBUG = false;
+    private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
+    private static final boolean IS_BACK_PREDICTABILITY_ENABLED = SystemProperties
+            .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
 
     /** The currently most prioritized callback. */
     @Nullable
@@ -82,6 +87,15 @@
     @Override
     public void registerOnBackInvokedCallback(
             @NonNull OnBackInvokedCallback callback, @Priority int priority) {
+        if (priority < 0) {
+            throw new IllegalArgumentException("Application registered OnBackInvokedCallback "
+                    + "cannot have negative priority. Priority: " + priority);
+        }
+        registerOnBackInvokedCallbackUnchecked(callback, priority);
+    }
+
+    private void registerOnBackInvokedCallbackUnchecked(
+            @NonNull OnBackInvokedCallback callback, @Priority int priority) {
         if (!mOnBackInvokedCallbacks.containsKey(priority)) {
             mOnBackInvokedCallbacks.put(priority, new ArrayList<>());
         }
@@ -120,6 +134,11 @@
         }
     }
 
+    @Override
+    public void registerSystemOnBackInvokedCallback(@NonNull OnBackInvokedCallback callback) {
+        registerOnBackInvokedCallbackUnchecked(callback, OnBackInvokedDispatcher.PRIORITY_SYSTEM);
+    }
+
     /** Clears all registered callbacks on the instance. */
     public void clear() {
         mAllCallbacks.clear();
@@ -198,4 +217,21 @@
             Handler.getMain().post(() -> mCallback.onBackInvoked());
         }
     }
+
+    @Override
+    public OnBackInvokedCallback getTopCallback() {
+        return mTopCallback == null ? null : mTopCallback.getCallback();
+    }
+
+    /**
+     * Returns if the legacy back behavior should be used.
+     *
+     * Legacy back behavior dispatches KEYCODE_BACK instead of invoking the application registered
+     * {@link android.view.OnBackInvokedCallback}.
+     *
+     */
+    public static boolean shouldUseLegacyBack() {
+        return !CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME)
+                || !IS_BACK_PREDICTABILITY_ENABLED;
+    }
 }
diff --git a/core/java/com/android/internal/app/BlockedAppActivity.java b/core/java/com/android/internal/app/BlockedAppActivity.java
index 65526eb..fbdbbfb 100644
--- a/core/java/com/android/internal/app/BlockedAppActivity.java
+++ b/core/java/com/android/internal/app/BlockedAppActivity.java
@@ -17,7 +17,6 @@
 package com.android.internal.app;
 
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
@@ -36,9 +35,6 @@
     private static final String TAG = "BlockedAppActivity";
     private static final String PACKAGE_NAME = "com.android.internal.app";
     private static final String EXTRA_BLOCKED_PACKAGE = PACKAGE_NAME + ".extra.BLOCKED_PACKAGE";
-    private static final String EXTRA_BLOCKED_ACTIVITY_INFO =
-            PACKAGE_NAME + ".extra.BLOCKED_ACTIVITY_INFO";
-    private static final String EXTRA_STREAMED_DEVICE = PACKAGE_NAME + ".extra.STREAMED_DEVICE";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -52,30 +48,17 @@
             return;
         }
 
-        CharSequence appLabel = null;
         String packageName = intent.getStringExtra(EXTRA_BLOCKED_PACKAGE);
-        ActivityInfo activityInfo = intent.getParcelableExtra(EXTRA_BLOCKED_ACTIVITY_INFO);
-        if (activityInfo != null) {
-            appLabel = activityInfo.loadLabel(getPackageManager());
-        } else if (!TextUtils.isEmpty(packageName)) {
-            appLabel = getAppLabel(userId, packageName);
-        }
-
-        if (TextUtils.isEmpty(appLabel)) {
-            Slog.wtf(TAG, "Invalid package: " + packageName + " or activity info: " + activityInfo);
+        if (TextUtils.isEmpty(packageName)) {
+            Slog.wtf(TAG, "Invalid package: " + packageName);
             finish();
             return;
         }
 
-        CharSequence streamedDeviceName = intent.getCharSequenceExtra(EXTRA_STREAMED_DEVICE);
-        if (!TextUtils.isEmpty(streamedDeviceName)) {
-            mAlertParams.mTitle = getString(R.string.app_streaming_blocked_title, appLabel);
-            mAlertParams.mMessage =
-                    getString(R.string.app_streaming_blocked_message, streamedDeviceName);
-        } else {
-            mAlertParams.mTitle = getString(R.string.app_blocked_title);
-            mAlertParams.mMessage = getString(R.string.app_blocked_message, appLabel);
-        }
+        CharSequence appLabel = getAppLabel(userId, packageName);
+
+        mAlertParams.mTitle = getString(R.string.app_blocked_title);
+        mAlertParams.mMessage = getString(R.string.app_blocked_message, appLabel);
         mAlertParams.mPositiveButtonText = getString(android.R.string.ok);
         setupAlert();
     }
@@ -100,19 +83,4 @@
                 .putExtra(Intent.EXTRA_USER_ID, userId)
                 .putExtra(EXTRA_BLOCKED_PACKAGE, packageName);
     }
-
-    /**
-     * Creates an intent that launches {@link BlockedAppActivity} when app streaming is blocked.
-     *
-     * Using this method and providing a non-empty {@code streamedDeviceName} will cause the dialog
-     * to use streaming-specific error messages.
-     */
-    public static Intent createStreamingBlockedIntent(int userId, ActivityInfo activityInfo,
-            CharSequence streamedDeviceName) {
-        return new Intent()
-                .setClassName("android", BlockedAppActivity.class.getName())
-                .putExtra(Intent.EXTRA_USER_ID, userId)
-                .putExtra(EXTRA_BLOCKED_ACTIVITY_INFO, activityInfo)
-                .putExtra(EXTRA_STREAMED_DEVICE, streamedDeviceName);
-    }
 }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 2925341..40e4085 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -87,7 +87,6 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
-import android.view.OnBackInvokedDispatcher;
 import android.view.PendingInsetsController;
 import android.view.ThreadedRenderer;
 import android.view.View;
@@ -109,7 +108,6 @@
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.PopupWindow;
-import android.window.WindowOnBackInvokedDispatcher;
 
 import com.android.internal.R;
 import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
@@ -297,7 +295,6 @@
         return true;
     };
     private Consumer<Boolean> mCrossWindowBlurEnabledListener;
-    private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
 
     DecorView(Context context, int featureId, PhoneWindow window,
             WindowManager.LayoutParams params) {
@@ -326,7 +323,6 @@
         initResizingPaints();
 
         mLegacyNavigationBarBackgroundPaint.setColor(Color.BLACK);
-        mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher();
     }
 
     void setBackgroundFallback(@Nullable Drawable fallbackDrawable) {
@@ -1880,7 +1876,6 @@
         }
 
         mPendingInsetsController.detach();
-        mOnBackInvokedDispatcher.detachFromWindow();
     }
 
     @Override
@@ -1925,11 +1920,6 @@
         return mPendingInsetsController;
     }
 
-    @Override
-    public WindowOnBackInvokedDispatcher provideWindowOnBackInvokedDispatcher() {
-        return mOnBackInvokedDispatcher;
-    }
-
     private ActionMode createActionMode(
             int type, ActionMode.Callback2 callback, View originatingView) {
         switch (type) {
@@ -2384,7 +2374,6 @@
                 }
             }
         }
-        mOnBackInvokedDispatcher.clear();
     }
 
     @Override
@@ -2666,15 +2655,6 @@
         }
     }
 
-    /**
-     * Returns the {@link OnBackInvokedDispatcher} on the decor view.
-     */
-    @Override
-    @Nullable
-    public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
-        return mOnBackInvokedDispatcher;
-    }
-
     @Override
     public String toString() {
         return "DecorView@" + Integer.toHexString(this.hashCode()) + "["
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 7755b69..12f38a4 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -91,6 +91,8 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.OnBackInvokedDispatcher;
+import android.view.OnBackInvokedDispatcherOwner;
 import android.view.ScrollCaptureCallback;
 import android.view.SearchEvent;
 import android.view.SurfaceHolder.Callback2;
@@ -110,6 +112,7 @@
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
+import android.window.ProxyOnBackInvokedDispatcher;
 
 import com.android.internal.R;
 import com.android.internal.view.menu.ContextMenuBuilder;
@@ -134,7 +137,8 @@
  *
  * @hide
  */
-public class PhoneWindow extends Window implements MenuBuilder.Callback {
+public class PhoneWindow extends Window implements MenuBuilder.Callback,
+        OnBackInvokedDispatcherOwner {
 
     private final static String TAG = "PhoneWindow";
 
@@ -340,6 +344,9 @@
 
     boolean mDecorFitsSystemWindows = true;
 
+    private ProxyOnBackInvokedDispatcher mProxyOnBackInvokedDispatcher =
+            new ProxyOnBackInvokedDispatcher();
+
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService("window"));
@@ -2146,6 +2153,7 @@
     /** Notify when decor view is attached to window and {@link ViewRootImpl} is available. */
     void onViewRootImplSet(ViewRootImpl viewRoot) {
         viewRoot.setActivityConfigCallback(mActivityConfigCallback);
+        mProxyOnBackInvokedDispatcher.setActualDispatcherOwner(viewRoot);
         applyDecorFitsSystemWindows();
     }
 
@@ -3993,4 +4001,10 @@
     public AttachedSurfaceControl getRootSurfaceControl() {
         return getViewRootImplOrNull();
     }
+
+    @NonNull
+    @Override
+    public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
+        return mProxyOnBackInvokedDispatcher;
+    }
 }
diff --git a/core/java/com/android/internal/util/dump/DumpableContainerImpl.java b/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
index d48b4b1..d391684 100644
--- a/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
+++ b/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
@@ -15,7 +15,6 @@
  */
 package com.android.internal.util.dump;
 
-import android.annotation.Nullable;
 import android.util.ArrayMap;
 import android.util.Dumpable;
 import android.util.DumpableContainer;
@@ -38,7 +37,6 @@
 
     private static final boolean DEBUG = false;
 
-    @Nullable
     private final ArrayMap<String, Dumpable> mDumpables = new ArrayMap<>();
 
     @Override
@@ -64,7 +62,7 @@
      * Dumps the number of dumpable, without a newline.
      */
     private int dumpNumberDumpables(IndentingPrintWriter writer) {
-        int size = mDumpables == null ? 0 : mDumpables.size();
+        int size = mDumpables.size();
         if (size == 0) {
             writer.print("No dumpables");
         } else {
@@ -102,7 +100,7 @@
             ipw.println();
             return;
         }
-        ipw.println(": ");
+        ipw.println(":");
 
         for (int i = 0; i < size; i++) {
             String dumpableName = mDumpables.keyAt(i);
diff --git a/core/java/com/android/internal/view/OneShotPreDrawListener.java b/core/java/com/android/internal/view/OneShotPreDrawListener.java
index 42d104a..c750c0b 100644
--- a/core/java/com/android/internal/view/OneShotPreDrawListener.java
+++ b/core/java/com/android/internal/view/OneShotPreDrawListener.java
@@ -15,6 +15,7 @@
  */
 package com.android.internal.view;
 
+import android.annotation.NonNull;
 import android.view.View;
 import android.view.ViewTreeObserver;
 
@@ -36,7 +37,8 @@
     private final Runnable mRunnable;
     private final boolean mReturnValue;
 
-    private OneShotPreDrawListener(View view, boolean returnValue, Runnable runnable) {
+    private OneShotPreDrawListener(@NonNull View view, boolean returnValue,
+            @NonNull Runnable runnable) {
         mView = view;
         mViewTreeObserver = view.getViewTreeObserver();
         mRunnable = runnable;
@@ -52,7 +54,7 @@
      * @return The added OneShotPreDrawListener. It can be removed prior to
      * the onPreDraw by calling {@link #removeListener()}.
      */
-    public static OneShotPreDrawListener add(View view, Runnable runnable) {
+    public static OneShotPreDrawListener add(@NonNull View view, @NonNull Runnable runnable) {
         return add(view, true, runnable);
     }
 
@@ -65,7 +67,8 @@
      * @return The added OneShotPreDrawListener. It can be removed prior to
      * the onPreDraw by calling {@link #removeListener()}.
      */
-    public static OneShotPreDrawListener add(View view, boolean returnValue, Runnable runnable) {
+    public static OneShotPreDrawListener add(@NonNull View view, boolean returnValue,
+            @NonNull Runnable runnable) {
         OneShotPreDrawListener listener = new OneShotPreDrawListener(view, returnValue, runnable);
         view.getViewTreeObserver().addOnPreDrawListener(listener);
         view.addOnAttachStateChangeListener(listener);
@@ -93,12 +96,12 @@
     }
 
     @Override
-    public void onViewAttachedToWindow(View v) {
+    public void onViewAttachedToWindow(@NonNull View v) {
         mViewTreeObserver = v.getViewTreeObserver();
     }
 
     @Override
-    public void onViewDetachedFromWindow(View v) {
+    public void onViewDetachedFromWindow(@NonNull View v) {
         removeListener();
     }
 }
diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
index 4b89bf508..3ab9a33 100644
--- a/core/java/com/android/internal/view/RootViewSurfaceTaker.java
+++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
@@ -15,12 +15,10 @@
  */
 package com.android.internal.view;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.view.InputQueue;
 import android.view.PendingInsetsController;
 import android.view.SurfaceHolder;
-import android.window.WindowOnBackInvokedDispatcher;
 
 /** hahahah */
 public interface RootViewSurfaceTaker {
@@ -31,6 +29,4 @@
     InputQueue.Callback willYouTakeTheInputQueue();
     void onRootViewScrollYChanged(int scrollY);
     @Nullable PendingInsetsController providePendingInsetsController();
-    /** @hide */
-    @NonNull WindowOnBackInvokedDispatcher provideWindowOnBackInvokedDispatcher();
 }
diff --git a/core/java/com/android/internal/widget/NestedScrollingChild.java b/core/java/com/android/internal/widget/NestedScrollingChild.java
index 20285b5..c7f5891 100644
--- a/core/java/com/android/internal/widget/NestedScrollingChild.java
+++ b/core/java/com/android/internal/widget/NestedScrollingChild.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import android.annotation.Nullable;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -149,7 +150,7 @@
      * @see #dispatchNestedPreScroll(int, int, int[], int[])
      */
     boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
-            int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow);
+            int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow);
 
     /**
      * Dispatch one step of a nested scroll in progress before this view consumes any portion of it.
@@ -170,7 +171,8 @@
      * @return true if the parent consumed some or all of the scroll delta
      * @see #dispatchNestedScroll(int, int, int, int, int[])
      */
-    boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow);
+    boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
+            @Nullable int[] offsetInWindow);
 
     /**
      * Dispatch a fling to a nested scrolling parent.
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 8bb9a0a..955f46b 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -309,8 +309,6 @@
                 "libdl_android",
                 "libtimeinstate",
                 "server_configurable_flags",
-                // TODO: delete when ConnectivityT moves to APEX.
-                "libframework-connectivity-tiramisu-jni",
             ],
             export_shared_lib_headers: [
                 // our headers include libnativewindow's public headers
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index edc8c5b..2bec733 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -18,25 +18,25 @@
 //#define LOG_NDEBUG 0
 
 #define LOG_TAG "AudioSystem-JNI"
-#include <utils/Log.h>
-
-#include <sstream>
-#include <vector>
-#include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-
 #include <android/media/AudioVibratorInfo.h>
 #include <android/media/INativeSpatializerCallback.h>
 #include <android/media/ISpatializer.h>
+#include <android_os_Parcel.h>
 #include <audiomanager/AudioManager.h>
+#include <jni.h>
 #include <media/AudioContainers.h>
 #include <media/AudioPolicy.h>
 #include <media/AudioSystem.h>
 #include <media/MicrophoneInfo.h>
+#include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedLocalRef.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
+#include <utils/Log.h>
+
+#include <sstream>
+#include <vector>
+
 #include "android_media_AudioAttributes.h"
 #include "android_media_AudioDescriptor.h"
 #include "android_media_AudioDeviceAttributes.h"
@@ -46,6 +46,7 @@
 #include "android_media_AudioProfile.h"
 #include "android_media_MicrophoneInfo.h"
 #include "android_util_Binder.h"
+#include "core_jni_helpers.h"
 
 // ----------------------------------------------------------------------------
 
@@ -584,18 +585,26 @@
     env->DeleteLocalRef(clazz);
 }
 
-static jint
-android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name,
-                                                   jint codec)
-{
-    const char *c_address = env->GetStringUTFChars(device_address, NULL);
-    const char *c_name = env->GetStringUTFChars(device_name, NULL);
-    int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
-                                          static_cast <audio_policy_dev_state_t>(state),
-                                          c_address, c_name,
-                                          static_cast <audio_format_t>(codec)));
-    env->ReleaseStringUTFChars(device_address, c_address);
-    env->ReleaseStringUTFChars(device_name, c_name);
+static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz,
+                                                               jint state, jobject jParcel,
+                                                               jint codec) {
+    int status;
+    if (Parcel *parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
+        android::media::audio::common::AudioPort port{};
+        if (status_t statusOfParcel = port.readFromParcel(parcel); statusOfParcel == OK) {
+            status = check_AudioSystem_Command(
+                    AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>(
+                                                                  state),
+                                                          port,
+                                                          static_cast<audio_format_t>(codec)));
+        } else {
+            ALOGE("Failed to read from parcel: %s", statusToString(statusOfParcel).c_str());
+            status = kAudioStatusError;
+        }
+    } else {
+        ALOGE("Failed to retrieve the native parcel from Java parcel");
+        status = kAudioStatusError;
+    }
     return (jint) status;
 }
 
@@ -2912,7 +2921,7 @@
          {"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
          {"newAudioPlayerId", "()I", (void *)android_media_AudioSystem_newAudioPlayerId},
          {"newAudioRecorderId", "()I", (void *)android_media_AudioSystem_newAudioRecorderId},
-         {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;I)I",
+         {"setDeviceConnectionState", "(ILandroid/os/Parcel;I)I",
           (void *)android_media_AudioSystem_setDeviceConnectionState},
          {"getDeviceConnectionState", "(ILjava/lang/String;)I",
           (void *)android_media_AudioSystem_getDeviceConnectionState},
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 61b91dd..13ca133 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -873,7 +873,7 @@
             const char* exceptionToThrow;
             char msg[128];
             // TransactionTooLargeException is a checked exception, only throw from certain methods.
-            // FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
+            // TODO(b/28321379): Transaction size is the most common cause for FAILED_TRANSACTION
             //        but it is not the only one.  The Binder driver can return BR_FAILED_REPLY
             //        for other reasons also, such as if the transaction is malformed or
             //        refers to an FD that has been closed.  We should change the driver
@@ -890,8 +890,9 @@
                 exceptionToThrow = (canThrowRemoteException)
                         ? "android/os/DeadObjectException"
                         : "java/lang/RuntimeException";
-                snprintf(msg, sizeof(msg)-1,
-                        "Transaction failed on small parcel; remote process probably died");
+                snprintf(msg, sizeof(msg) - 1,
+                         "Transaction failed on small parcel; remote process probably died, but "
+                         "this could also be caused by running out of binder buffer space");
             }
             jniThrowException(env, exceptionToThrow, msg);
         } break;
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 7c67cbc..a6fbf094 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -235,9 +235,7 @@
 void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
 {
     ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
-    DIR *d;
     char proc_path[255];
-    struct dirent *de;
 
     if (!verifyGroup(env, grp)) {
         return;
@@ -277,84 +275,8 @@
         }
     }
 
-    sprintf(proc_path, "/proc/%d/task", pid);
-    if (!(d = opendir(proc_path))) {
-        // If the process exited on us, don't generate an exception
-        if (errno != ENOENT)
-            signalExceptionForGroupError(env, errno, pid);
-        return;
-    }
-
-    while ((de = readdir(d))) {
-        int t_pid;
-        int t_pri;
-        std::string taskprofile;
-
-        if (de->d_name[0] == '.')
-            continue;
-        t_pid = atoi(de->d_name);
-
-        if (!t_pid) {
-            ALOGE("Error getting pid for '%s'\n", de->d_name);
-            continue;
-        }
-
-        t_pri = getpriority(PRIO_PROCESS, t_pid);
-
-        if (t_pri <= ANDROID_PRIORITY_AUDIO) {
-            int scheduler = sched_getscheduler(t_pid) & ~SCHED_RESET_ON_FORK;
-            if ((scheduler == SCHED_FIFO) || (scheduler == SCHED_RR)) {
-                // This task wants to stay in its current audio group so it can keep its budget
-                // don't update its cpuset or cgroup
-                continue;
-            }
-        }
-
-        errno = 0;
-        // grp == SP_BACKGROUND. Set background cpuset policy profile for all threads.
-        if (grp == SP_BACKGROUND) {
-            if (!SetTaskProfiles(t_pid, {"CPUSET_SP_BACKGROUND"}, true)) {
-                signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
-                break;
-            }
-            continue;
-        }
-
-        // grp != SP_BACKGROUND. Only change the cpuset cgroup for low priority thread, so it could
-        // preserve it sched policy profile setting.
-        if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
-            switch (grp) {
-                case SP_SYSTEM:
-                    taskprofile = "ServiceCapacityLow";
-                    break;
-                case SP_RESTRICTED:
-                    taskprofile = "ServiceCapacityRestricted";
-                    break;
-                case SP_FOREGROUND:
-                case SP_AUDIO_APP:
-                case SP_AUDIO_SYS:
-                    taskprofile = "ProcessCapacityHigh";
-                    break;
-                case SP_TOP_APP:
-                    taskprofile = "ProcessCapacityMax";
-                    break;
-                default:
-                    taskprofile = "ProcessCapacityNormal";
-                    break;
-            }
-            if (!SetTaskProfiles(t_pid, {taskprofile}, true)) {
-                signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
-                break;
-            }
-        // Change the cpuset policy profile for non-low priority thread according to the grp
-        } else {
-            if (!SetTaskProfiles(t_pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}, true)) {
-                signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
-                break;
-            }
-        }
-    }
-    closedir(d);
+    if (!SetProcessProfilesCached(0, pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}))
+        signalExceptionForGroupError(env, errno ? errno : EPERM, pid);
 }
 
 void android_os_Process_setProcessFrozen(
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 9915913..1033efa5 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -2168,7 +2168,7 @@
             (void*)nativeGetLayerId },
     {"nativeSetDropInputMode", "(JJI)V",
              (void*)nativeSetDropInputMode },
-    {"nativeAddTransactionCommittedListener", "(JLandroid/view/TransactionCommittedListener;)V",
+    {"nativeAddTransactionCommittedListener", "(JLandroid/view/SurfaceControl$TransactionCommittedListener;)V",
             (void*) nativeAddTransactionCommittedListener },
     {"nativeSanitize", "(J)V",
             (void*) nativeSanitize }
@@ -2393,7 +2393,7 @@
                              "([Landroid/view/SurfaceControl$JankData;)V");
 
     jclass transactionCommittedListenerClazz =
-            FindClassOrDie(env, "android/view/TransactionCommittedListener");
+            FindClassOrDie(env, "android/view/SurfaceControl$TransactionCommittedListener");
     gTransactionCommittedListenerClassInfo.clazz =
             MakeGlobalRefOrDie(env, transactionCommittedListenerClazz);
     gTransactionCommittedListenerClassInfo.onTransactionCommitted =
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index aacf700..5efc4db 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -202,6 +202,8 @@
  */
 static constexpr int STORAGE_DIR_CHECK_TIMEOUT_US = 1000 * 1000 * 60 * 5;
 
+static void WaitUntilDirReady(const std::string& target, fail_fn_t fail_fn);
+
 /**
  * A helper class containing accounting information for USAPs.
  */
@@ -1249,7 +1251,11 @@
     auto volPath = StringPrintf("%s/%s", externalPrivateMountPath, ent->d_name);
     auto cePath = StringPrintf("%s/user", volPath.c_str());
     auto dePath = StringPrintf("%s/user_de", volPath.c_str());
+    // Wait until dir user is created.
+    WaitUntilDirReady(cePath.c_str(), fail_fn);
     MountAppDataTmpFs(cePath.c_str(), fail_fn);
+    // Wait until dir user_de is created.
+    WaitUntilDirReady(dePath.c_str(), fail_fn);
     MountAppDataTmpFs(dePath.c_str(), fail_fn);
   }
   closedir(dir);
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index d48ea3b..04f4d7b 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -452,16 +452,16 @@
     optional bool is_interactive = 5;
 
     // Time (in elapsedRealtime) when the device was last interactive
-    optional bool last_interactive_time = 6;
+    optional int64 last_interactive_time = 6;
 
-    // Time (in milliseconds) after becoming non-interactive that Low Power Standby can activate
+    // Timeout (in milliseconds) after becoming non-interactive that Low Power Standby can activate
     optional int32 standby_timeout_config = 7;
 
     // True if the device has entered idle mode since becoming non-interactive
-    optional int32 idle_since_non_interactive = 8;
+    optional bool idle_since_non_interactive = 8;
 
     // True if the device is currently in idle mode
-    optional int32 is_device_idle = 9;
+    optional bool is_device_idle = 9;
 
     // Set of app ids that are exempt form low power standby
     repeated int32 allowlist = 10;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9db715b..74bf152 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -398,6 +398,7 @@
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED" />
+    <protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_RESOURCE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
     <protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
@@ -977,6 +978,61 @@
         android:permissionFlags="softRestricted|immutablyRestricted"
         android:protectionLevel="dangerous" />
 
+    <!-- Required to be able to read audio files from shared storage.
+     <p>Protection level: dangerous -->
+    <permission-group android:name="android.permission-group.READ_MEDIA_AURAL"
+                      android:icon="@drawable/perm_group_read_media_aural"
+                      android:label="@string/permgrouplab_readMediaAural"
+                      android:description="@string/permgroupdesc_readMediaAural"
+                      android:priority="950" />
+
+    <!-- Allows an application to read audio files from external storage.
+      <p>This permission is enforced starting in API level
+      {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+      For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+      targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
+      must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+     <p>Protection level: dangerous -->
+    <permission android:name="android.permission.READ_MEDIA_AUDIO"
+                android:permissionGroup="android.permission-group.UNDEFINED"
+                android:label="@string/permlab_readMediaAudio"
+                android:description="@string/permdesc_readMediaAudio"
+                android:protectionLevel="dangerous" />
+
+    <!-- Required to be able to read image and video files from shared storage.
+     <p>Protection level: dangerous -->
+    <permission-group android:name="android.permission-group.READ_MEDIA_VISUAL"
+                      android:icon="@drawable/perm_group_read_media_visual"
+                      android:label="@string/permgrouplab_readMediaVisual"
+                      android:description="@string/permgroupdesc_readMediaVisual"
+                      android:priority="1000" />
+
+    <!-- Allows an application to read audio files from external storage.
+    <p>This permission is enforced starting in API level
+    {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+    For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+    targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
+    must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+   <p>Protection level: dangerous -->
+    <permission android:name="android.permission.READ_MEDIA_VIDEO"
+                android:permissionGroup="android.permission-group.UNDEFINED"
+                android:label="@string/permlab_readMediaVideo"
+                android:description="@string/permdesc_readMediaVideo"
+                android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to read image files from external storage.
+      <p>This permission is enforced starting in API level
+      {@link android.os.Build.VERSION_CODES#TIRAMISU}.
+      For apps with a <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+      targetSdkVersion}</a> of {@link android.os.Build.VERSION_CODES#S} or lower, this permission
+      must not be used and the READ_EXTERNAL_STORAGE permission must be used instead.
+     <p>Protection level: dangerous -->
+    <permission android:name="android.permission.READ_MEDIA_IMAGE"
+                android:permissionGroup="android.permission-group.UNDEFINED"
+                android:label="@string/permlab_readMediaImage"
+                android:description="@string/permdesc_readMediaImage"
+                android:protectionLevel="dangerous" />
+
     <!-- Allows an application to write to external storage.
          <p class="note"><strong>Note:</strong> If <em>both</em> your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
@@ -2027,6 +2083,11 @@
     <permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi @hide Allows an application to manage ethernet networks.
+         <p>Not for use by third-party or privileged applications. -->
+    <permission android:name="android.permission.MANAGE_ETHERNET_NETWORKS"
+        android:protectionLevel="signature" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
@@ -6554,6 +6615,13 @@
                   android:exported="false">
         </activity>
 
+        <activity android:name="android.service.games.GameSessionTrampolineActivity"
+                  android:excludeFromRecents="true"
+                  android:exported="true"
+                  android:permission="android.permission.MANAGE_GAME_ACTIVITY"
+                  android:theme="@style/Theme.Translucent.NoTitleBar">
+        </activity>
+
         <receiver android:name="com.android.server.BootReceiver"
                 android:exported="true"
                 android:systemUserOnly="true">
diff --git a/core/res/res/drawable/perm_group_read_media_aural.xml b/core/res/res/drawable/perm_group_read_media_aural.xml
new file mode 100644
index 0000000..6fc9c69
--- /dev/null
+++ b/core/res/res/drawable/perm_group_read_media_aural.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M10,21q-1.65,0 -2.825,-1.175Q6,18.65 6,17q0,-1.65 1.175,-2.825Q8.35,13 10,13q0.575,0 1.063,0.137 0.487,0.138 0.937,0.413V3h6v4h-4v10q0,1.65 -1.175,2.825Q11.65,21 10,21z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/perm_group_read_media_visual.xml b/core/res/res/drawable/perm_group_read_media_visual.xml
new file mode 100644
index 0000000..a5db271
--- /dev/null
+++ b/core/res/res/drawable/perm_group_read_media_visual.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M9,14h10l-3.45,-4.5 -2.3,3 -1.55,-2zM8,18q-0.825,0 -1.412,-0.587Q6,16.825 6,16L6,4q0,-0.825 0.588,-1.413Q7.175,2 8,2h12q0.825,0 1.413,0.587Q22,3.175 22,4v12q0,0.825 -0.587,1.413Q20.825,18 20,18zM8,16h12L20,4L8,4v12zM4,22q-0.825,0 -1.413,-0.587Q2,20.825 2,20L2,6h2v14h14v2zM8,4v12L8,4z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index afe0f1b..d774fd4 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6953,10 +6953,10 @@
     </declare-styleable>
 
     <declare-styleable name="TranslateAnimation">
-        <attr name="fromXDelta" format="float|fraction" />
-        <attr name="toXDelta" format="float|fraction" />
-        <attr name="fromYDelta" format="float|fraction" />
-        <attr name="toYDelta" format="float|fraction" />
+        <attr name="fromXDelta" format="float|fraction|dimension" />
+        <attr name="toXDelta" format="float|fraction|dimension" />
+        <attr name="fromYDelta" format="float|fraction|dimension" />
+        <attr name="toYDelta" format="float|fraction|dimension" />
     </declare-styleable>
 
     <declare-styleable name="AlphaAnimation">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 3a2fb6e..cb40e86 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2839,6 +2839,14 @@
         <attr name="path" />
         <attr name="minSdkVersion" />
         <attr name="maxSdkVersion" />
+        <!-- The order in which the apex system services are initiated. When there are dependencies
+        among apex system services, setting this attribute for each of them ensures that they are
+        created in the order required by those dependencies. The apex-system-services that are
+        started manually within SystemServer ignore the initOrder and are not considered for
+        automatic starting of the other services.
+        The value is a simple integer, with higher number being initialized first. If not specified,
+        the default order is 0. -->
+        <attr name="initOrder" format="integer" />
     </declare-styleable>
 
     <!-- The <code>receiver</code> tag declares an
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 59d6005..54325e5 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -448,4 +448,7 @@
     <color name="accessibility_magnification_background">#F50D60</color>
     <color name="accessibility_daltonizer_background">#00BCD4</color>
     <color name="accessibility_color_inversion_background">#546E7A</color>
+
+    <!-- Color of camera light when camera is in use -->
+    <color name="camera_privacy_light">#FFFFFF</color>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0dbd417..47b4d38 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -876,9 +876,19 @@
     <string name="permgroupdesc_sms">send and view SMS messages</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_storage">Files and media</string>
+    <string name="permgrouplab_storage">Files &amp; documents</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_storage">access photos, media, and files on your device</string>
+    <string name="permgroupdesc_storage">access files and documents on your device</string>
+
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
+    <string name="permgrouplab_readMediaAural">Music &amp; other audio</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
+    <string name="permgroupdesc_readMediaAural">access audio files on your device</string>
+
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=40]-->
+    <string name="permgrouplab_readMediaVisual">Photos &amp; videos</string>
+    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
+    <string name="permgroupdesc_readMediaVisual">access images and video files on your device</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_microphone">Microphone</string>
@@ -1893,6 +1903,21 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
     <string name="permdesc_sdcardRead">Allows the app to read the contents of your shared storage.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permlab_readMediaAudio">read audio files from shared storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permdesc_readMediaAudio">Allows the app to read audio files from your shared storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permlab_readMediaVideo">read video files from shared storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permdesc_readMediaVideo">Allows the app to read video files from your shared storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permlab_readMediaImage">read image files from shared storage</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+    <string name="permdesc_readMediaImage">Allows the app to read image files from your shared storage.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] -->
     <string name="permlab_sdcardWrite">modify or delete the contents of your shared storage</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] -->
@@ -5439,15 +5464,6 @@
         <xliff:g id="app_name" example="Gmail">%1$s</xliff:g> is not available right now.
     </string>
 
-    <!-- Title of the dialog shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
-    <string name="app_streaming_blocked_title"><xliff:g id="activity" example="Permission dialog">%1$s</xliff:g> unavailable</string>
-    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
-    <string name="app_streaming_blocked_message" product="tv">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your Android TV device instead.</string>
-    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
-    <string name="app_streaming_blocked_message" product="tablet">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your tablet instead.</string>
-    <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
-    <string name="app_streaming_blocked_message" product="default">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your phone instead.</string>
-
     <!-- Message displayed in dialog when app is too old to run on this verison of android. [CHAR LIMIT=NONE] -->
     <string name="deprecated_target_sdk_message">This app was built for an older version of Android and may not work properly. Try checking for updates, or contact the developer.</string>
     <!-- Title for button to see application detail in app store which it came from - it may allow user to update to newer version. [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 764b273..2b25c3e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3285,9 +3285,6 @@
   <java-symbol type="string" name="app_blocked_title" />
   <java-symbol type="string" name="app_blocked_message" />
 
-  <java-symbol type="string" name="app_streaming_blocked_title" />
-  <java-symbol type="string" name="app_streaming_blocked_message" />
-
   <!-- Used internally for assistant to launch activity transitions -->
   <java-symbol type="id" name="cross_task_transition" />
 
@@ -4725,4 +4722,6 @@
   <java-symbol type="bool" name="config_lowPowerStandbySupported" />
   <java-symbol type="bool" name="config_lowPowerStandbyEnabledByDefault" />
   <java-symbol type="integer" name="config_lowPowerStandbyNonInteractiveTimeout" />
+
+  <java-symbol type="color" name="camera_privacy_light"/>
 </resources>
diff --git a/core/tests/bandwidthtests/Android.bp b/core/tests/bandwidthtests/Android.bp
index f1ecd45..d0b42f7 100644
--- a/core/tests/bandwidthtests/Android.bp
+++ b/core/tests/bandwidthtests/Android.bp
@@ -23,6 +23,7 @@
 
 android_test {
     name: "BandwidthTests",
+    defaults: ["framework-connectivity-test-defaults"],
     // Include all test java files.
     srcs: ["src/**/*.java"],
     libs: [
diff --git a/core/tests/benchmarks/Android.bp b/core/tests/benchmarks/Android.bp
index 4cd5467..0888776 100644
--- a/core/tests/benchmarks/Android.bp
+++ b/core/tests/benchmarks/Android.bp
@@ -27,6 +27,7 @@
 
 java_library {
     name: "frameworks-base-core-benchmarks",
+    defaults: ["framework-connectivity-test-defaults"],
     installable: true,
     srcs: ["src/**/*.java"],
     libs: ["caliper-api-target"],
diff --git a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
index 3c8f90c..6360a2d 100644
--- a/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
+++ b/core/tests/coretests/src/android/net/NetworkPolicyTest.kt
@@ -16,7 +16,9 @@
 
 package android.net
 
+import android.net.NetworkStats.METERED_YES
 import android.net.NetworkTemplate.MATCH_BLUETOOTH
+import android.net.NetworkTemplate.MATCH_CARRIER
 import android.net.NetworkTemplate.MATCH_ETHERNET
 import android.net.NetworkTemplate.MATCH_MOBILE
 import android.net.NetworkTemplate.MATCH_WIFI
@@ -39,11 +41,19 @@
     @Test
     fun testTemplateBackupRestore() {
         assertPolicyBackupRestore(createTestPolicyForTemplate(
-                NetworkTemplate.buildTemplateWifi(TEST_WIFI_NETWORK_KEY1)))
+                NetworkTemplate.Builder(MATCH_WIFI)
+                    .setWifiNetworkKeys(setOf(TEST_WIFI_NETWORK_KEY1))
+                    .build()))
         assertPolicyBackupRestore(createTestPolicyForTemplate(
-                NetworkTemplate.buildTemplateMobileAll(TEST_IMSI1)))
+                NetworkTemplate.Builder(MATCH_MOBILE)
+                    .setSubscriberIds(setOf(TEST_IMSI1))
+                    .setMeteredness(METERED_YES)
+                    .build()))
         assertPolicyBackupRestore(createTestPolicyForTemplate(
-                NetworkTemplate.buildTemplateCarrierMetered(TEST_IMSI1)))
+                NetworkTemplate.Builder(MATCH_CARRIER)
+                    .setSubscriberIds(setOf(TEST_IMSI1))
+                    .setMeteredness(METERED_YES)
+                    .build()))
     }
 
     private fun createTestPolicyForTemplate(template: NetworkTemplate): NetworkPolicy {
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
index 6df9002..ddc27aa 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java
@@ -42,7 +42,7 @@
     // and assertAccessibilityEventCleared
 
     /** The number of properties of the {@link AccessibilityEvent} class. */
-    private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 32;
+    private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 33;
 
     // The number of fields tested in the corresponding CTS AccessibilityRecordTest:
     // assertAccessibilityRecordCleared, fullyPopulateAccessibilityRecord,
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 02e5942..fc385a0 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -204,4 +204,6 @@
 
     public void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
             int processId, long threadId, int callingUid, Bundle serializedCallingStackInBundle) {}
+
+    public void setAnimationScale(float scale) {}
 }
diff --git a/core/tests/coretests/src/android/window/BackNavigationTest.java b/core/tests/coretests/src/android/window/BackNavigationTest.java
new file mode 100644
index 0000000..91d8531
--- /dev/null
+++ b/core/tests/coretests/src/android/window/BackNavigationTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 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.window;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.app.ActivityTaskManager;
+import android.app.EmptyActivity;
+import android.app.Instrumentation;
+import android.os.RemoteException;
+import android.support.test.uiautomator.UiDevice;
+import android.view.OnBackInvokedCallback;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Integration test for back navigation
+ */
+public class BackNavigationTest {
+
+    @Rule
+    public final ActivityScenarioRule<EmptyActivity> mScenarioRule =
+            new ActivityScenarioRule<>(EmptyActivity.class);
+    private ActivityScenario<EmptyActivity> mScenario;
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setup() {
+        mScenario = mScenarioRule.getScenario();
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        try {
+            UiDevice.getInstance(mInstrumentation).wakeUp();
+        } catch (RemoteException ignored) {
+        }
+        mInstrumentation.getUiAutomation().adoptShellPermissionIdentity();
+    }
+
+    @Test
+    public void registerCallback_initialized() {
+        CountDownLatch latch = registerBackCallback();
+        mScenario.moveToState(Lifecycle.State.RESUMED);
+        assertCallbackIsCalled(latch);
+    }
+
+    @Test
+    public void registerCallback_created() {
+        mScenario.moveToState(Lifecycle.State.CREATED);
+        CountDownLatch latch = registerBackCallback();
+        mScenario.moveToState(Lifecycle.State.STARTED);
+        mScenario.moveToState(Lifecycle.State.RESUMED);
+        assertCallbackIsCalled(latch);
+    }
+
+    @Test
+    public void registerCallback_resumed() {
+        mScenario.moveToState(Lifecycle.State.CREATED);
+        mScenario.moveToState(Lifecycle.State.STARTED);
+        mScenario.moveToState(Lifecycle.State.RESUMED);
+        CountDownLatch latch = registerBackCallback();
+        assertCallbackIsCalled(latch);
+    }
+
+    private void assertCallbackIsCalled(CountDownLatch latch) {
+        try {
+            mInstrumentation.getUiAutomation().waitForIdle(500, 1000);
+            BackNavigationInfo info = ActivityTaskManager.getService().startBackNavigation();
+            assertNotNull("BackNavigationInfo is null", info);
+            assertNotNull("OnBackInvokedCallback is null", info.getOnBackInvokedCallback());
+            info.getOnBackInvokedCallback().onBackInvoked();
+            assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
+        } catch (RemoteException ex) {
+            ex.rethrowFromSystemServer();
+        } catch (InterruptedException ex) {
+            fail("Application died before invoking the callback.\n" + ex.getMessage());
+        } catch (TimeoutException ex) {
+            fail(ex.getMessage());
+        }
+    }
+
+    @NonNull
+    private CountDownLatch registerBackCallback() {
+        CountDownLatch backInvokedLatch = new CountDownLatch(1);
+        CountDownLatch backRegisteredLatch = new CountDownLatch(1);
+        mScenario.onActivity(activity -> {
+            activity.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+                    new OnBackInvokedCallback() {
+                        @Override
+                        public void onBackInvoked() {
+                            backInvokedLatch.countDown();
+                        }
+                    }, 0
+            );
+            backRegisteredLatch.countDown();
+        });
+        try {
+            if (!backRegisteredLatch.await(100, TimeUnit.MILLISECONDS)) {
+                fail("Back callback was not registered on the Activity thread. This might be "
+                        + "an error with the test itself.");
+            }
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        }
+        return backInvokedLatch;
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
index c20293b..95225b2 100644
--- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.os;
 
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_NO;
 import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -94,7 +97,8 @@
 
         // Note application network activity
         NetworkStats networkStats = new NetworkStats(10000, 1)
-                .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100);
+                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
+                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100));
         mStatsRule.setNetworkStats(networkStats);
 
         ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000,
@@ -160,7 +164,8 @@
 
         // Note application network activity
         mStatsRule.setNetworkStats(new NetworkStats(10000, 1)
-                .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100));
+                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100)));
 
         stats.noteModemControllerActivity(null, POWER_DATA_UNAVAILABLE, 10000, 10000,
                 mNetworkStatsManager);
@@ -169,7 +174,8 @@
                 BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 11000);
 
         mStatsRule.setNetworkStats(new NetworkStats(12000, 1)
-                .insertEntry("cellular", APP_UID, 0, 0, 1000, 250, 2000, 80, 200));
+                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 250, 2000, 80, 200)));
 
         stats.noteModemControllerActivity(null, POWER_DATA_UNAVAILABLE, 12000, 12000,
                 mNetworkStatsManager);
@@ -241,7 +247,8 @@
 
         // Note application network activity
         NetworkStats networkStats = new NetworkStats(10000, 1)
-                .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100);
+                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
+                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100));
         mStatsRule.setNetworkStats(networkStats);
 
         ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000,
@@ -306,7 +313,8 @@
 
         // Note application network activity
         mStatsRule.setNetworkStats(new NetworkStats(10000, 1)
-                .insertEntry("cellular", APP_UID, 0, 0, 1000, 100, 2000, 20, 100));
+                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 100, 2000, 20, 100)));
 
         stats.noteModemControllerActivity(null, 10_000_000, 10000, 10000, mNetworkStatsManager);
 
@@ -314,7 +322,8 @@
                 BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 11000);
 
         mStatsRule.setNetworkStats(new NetworkStats(12000, 1)
-                .insertEntry("cellular", APP_UID, 0, 0, 1000, 250, 2000, 80, 200));
+                .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
+                    METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000, 250, 2000, 80, 200)));
 
         stats.noteModemControllerActivity(null, 15_000_000, 12000, 12000, mNetworkStatsManager);
 
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
index a368399..f74e72b 100644
--- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -17,6 +17,9 @@
 package com.android.internal.os;
 
 
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_NO;
 import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -77,8 +80,12 @@
     private NetworkStats buildNetworkStats(long elapsedRealtime, int rxBytes, int rxPackets,
             int txBytes, int txPackets) {
         return new NetworkStats(elapsedRealtime, 1)
-                .insertEntry("wifi", APP_UID, 0, 0, rxBytes, rxPackets, txBytes, txPackets, 100)
-                .insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
+                .addEntry(new NetworkStats.Entry("wifi", APP_UID, 0, 0,
+                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, rxPackets,
+                        txBytes, txPackets, 100))
+                .addEntry(new NetworkStats.Entry("wifi", Process.WIFI_UID, 0, 0,
+                        METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1111, 111,
+                        2222, 22, 111));
     }
 
     /** Sets up an WifiActivityEnergyInfo for ActivityController-model-based tests. */
diff --git a/core/tests/utillib/Android.bp b/core/tests/utillib/Android.bp
index d40d1d2..1d5c16c 100644
--- a/core/tests/utillib/Android.bp
+++ b/core/tests/utillib/Android.bp
@@ -23,6 +23,7 @@
 
 java_library {
     name: "frameworks-core-util-lib",
+    defaults: ["framework-connectivity-test-defaults"],
 
     srcs: ["**/*.java"],
 
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 92fca36..88920c8 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -231,6 +231,18 @@
                       targetSdk="29">
         <new-permission name="android.permission.ACCESS_MEDIA_LOCATION" />
     </split-permission>
+    <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
+                      targetSdk="33">
+        <new-permission name="android.permission.READ_MEDIA_AUDIO" />
+    </split-permission>
+    <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
+                      targetSdk="33">
+        <new-permission name="android.permission.READ_MEDIA_VIDEO" />
+    </split-permission>
+    <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
+                      targetSdk="33">
+        <new-permission name="android.permission.READ_MEDIA_IMAGE" />
+    </split-permission>
     <split-permission name="android.permission.BLUETOOTH"
                       targetSdk="31">
         <new-permission name="android.permission.BLUETOOTH_SCAN" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a331b6e..83c4024 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -334,6 +334,7 @@
         <permission name="android.permission.MANAGE_ACCESSIBILITY"/>
         <permission name="android.permission.MANAGE_DEVICE_ADMINS"/>
         <permission name="android.permission.MANAGE_GAME_MODE"/>
+        <permission name="android.permission.MANAGE_GAME_ACTIVITY" />
         <permission name="android.permission.MANAGE_LOW_POWER_STANDBY" />
         <permission name="android.permission.MANAGE_ROLLBACKS"/>
         <permission name="android.permission.MANAGE_USB"/>
@@ -400,6 +401,7 @@
         <!-- Permission required for CTS test - TrustTestCases -->
         <permission name="android.permission.PROVIDE_TRUST_AGENT" />
         <permission name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
+        <permission name="android.permission.TRUST_LISTENER" />
         <!-- Permissions required for Incremental CTS tests -->
         <permission name="com.android.permission.USE_INSTALLER_V2"/>
         <permission name="android.permission.LOADER_USAGE_STATS"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 1567233..f2a875c7 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -727,12 +727,6 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "-1343787701": {
-      "message": "startBackNavigation task=%s, topRunningActivity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
     "-1340540100": {
       "message": "Creating SnapshotStartingData",
       "level": "VERBOSE",
@@ -1765,6 +1759,12 @@
       "group": "WM_DEBUG_SYNC_ENGINE",
       "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
     },
+    "-228813488": {
+      "message": "%s: Setting back callback %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
     "-208825711": {
       "message": "shouldWaitAnimatingExit: isWallpaperTarget: %s",
       "level": "DEBUG",
@@ -3691,6 +3691,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "1898905572": {
+      "message": "startBackNavigation task=%s, topRunningActivity=%s, topWindow=%s backCallback=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
     "1903353011": {
       "message": "notifyAppStopped: %s",
       "level": "VERBOSE",
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 3732285..1629b6a 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -368,7 +368,7 @@
      * Further, unlike other Sources, this one is not reusable.
      */
     private static class InputStreamSource extends Source {
-        InputStreamSource(Resources res, InputStream is, int inputDensity) {
+        InputStreamSource(Resources res, @NonNull InputStream is, int inputDensity) {
             if (is == null) {
                 throw new IllegalArgumentException("The InputStream cannot be null");
             }
@@ -1020,7 +1020,7 @@
      */
     @AnyThread
     @NonNull
-    public static Source createSource(Resources res, InputStream is) {
+    public static Source createSource(Resources res, @NonNull InputStream is) {
         return new InputStreamSource(res, is, Bitmap.getDefaultDensity());
     }
 
@@ -1034,7 +1034,7 @@
     @AnyThread
     @TestApi
     @NonNull
-    public static Source createSource(Resources res, InputStream is, int density) {
+    public static Source createSource(Resources res, @NonNull InputStream is, int density) {
         return new InputStreamSource(res, is, density);
     }
 
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 57046f5..2ff888b 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -34,8 +34,6 @@
                 RuntimeShader.class.getClassLoader(), nativeGetFinalizer());
     }
 
-    private boolean mForceOpaque;
-
     /**
      * Current native shader builder instance.
      */
@@ -47,33 +45,17 @@
      * @param shader The text of AGSL shader program to run.
      */
     public RuntimeShader(@NonNull String shader) {
-        this(shader, false);
-    }
-
-    /**
-     * Creates a new RuntimeShader.
-     *
-     * @param shader The text of AGSL shader program to run.
-     * @param forceOpaque If true then all pixels produced by the AGSL shader program will have an
-     *                    alpha of 1.0f.
-     */
-    public RuntimeShader(@NonNull String shader, boolean forceOpaque) {
         // colorspace is required, but the RuntimeShader always produces colors in the destination
         // buffer's colorspace regardless of the value specified here.
         super(ColorSpace.get(ColorSpace.Named.SRGB));
         if (shader == null) {
             throw new NullPointerException("RuntimeShader requires a non-null AGSL string");
         }
-        mForceOpaque = forceOpaque;
         mNativeInstanceRuntimeShaderBuilder = nativeCreateBuilder(shader);
         NoImagePreloadHolder.sRegistry.registerNativeAllocation(
                 this, mNativeInstanceRuntimeShaderBuilder);
     }
 
-    public boolean isForceOpaque() {
-        return mForceOpaque;
-    }
-
     /**
      * Sets the uniform color value corresponding to this shader.  If the shader does not have a
      * uniform with that name or if the uniform is declared with a type other than vec3 or vec4 and
@@ -322,7 +304,7 @@
     /** @hide */
     @Override
     protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
-        return nativeCreateShader(mNativeInstanceRuntimeShaderBuilder, nativeMatrix, mForceOpaque);
+        return nativeCreateShader(mNativeInstanceRuntimeShaderBuilder, nativeMatrix);
     }
 
     /** @hide */
@@ -332,8 +314,7 @@
 
     private static native long nativeGetFinalizer();
     private static native long nativeCreateBuilder(String agsl);
-    private static native long nativeCreateShader(
-            long shaderBuilder, long matrix, boolean isOpaque);
+    private static native long nativeCreateShader(long shaderBuilder, long matrix);
     private static native void nativeUpdateUniforms(
             long shaderBuilder, String uniformName, float[] uniforms, boolean isColor);
     private static native void nativeUpdateUniforms(
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 28b3b04..4972e92 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -288,8 +288,7 @@
      *
      * @return A copy of the drawable's bounds
      */
-    @NonNull
-    public final Rect copyBounds() {
+    public final @NonNull Rect copyBounds() {
         return new Rect(mBounds);
     }
 
@@ -308,8 +307,7 @@
      * @see #copyBounds()
      * @see #copyBounds(android.graphics.Rect)
      */
-    @NonNull
-    public final Rect getBounds() {
+    public final @NonNull Rect getBounds() {
         if (mBounds == ZERO_BOUNDS_RECT) {
             mBounds = new Rect();
         }
@@ -327,8 +325,7 @@
      *
      * @return The dirty bounds of this drawable
      */
-    @NonNull
-    public Rect getDirtyBounds() {
+    public @NonNull Rect getDirtyBounds() {
         return getBounds();
     }
 
@@ -457,8 +454,7 @@
      *
      * @see #setCallback(android.graphics.drawable.Drawable.Callback)
      */
-    @Nullable
-    public Callback getCallback() {
+    public @Nullable Callback getCallback() {
         return mCallback != null ? mCallback.get() : null;
     }
 
@@ -569,8 +565,7 @@
      * The default return value is 255 if the class does not override this method to return a value
      * specific to its use of alpha.
      */
-    @IntRange(from=0,to=255)
-    public int getAlpha() {
+    public @IntRange(from=0,to=255) int getAlpha() {
         return 0xFF;
     }
 
@@ -999,7 +994,8 @@
      *
      * @see android.graphics.PixelFormat
      */
-    @Deprecated public abstract @PixelFormat.Opacity int getOpacity();
+    @Deprecated
+    public abstract @PixelFormat.Opacity int getOpacity();
 
     /**
      * Return the appropriate opacity value for two source opacities.  If
@@ -1059,7 +1055,7 @@
      * if it looks the same and there is no need to redraw it since its
      * last state.
      */
-    protected boolean onStateChange(int[] state) {
+    protected boolean onStateChange(@NonNull int[] state) {
         return false;
     }
 
@@ -1078,7 +1074,7 @@
      * Override this in your subclass to change appearance if you vary based on
      * the bounds.
      */
-    protected void onBoundsChange(Rect bounds) {
+    protected void onBoundsChange(@NonNull Rect bounds) {
         // Stub method.
     }
 
@@ -1209,7 +1205,8 @@
     /**
      * Create a drawable from an inputstream
      */
-    public static Drawable createFromStream(InputStream is, String srcName) {
+    public static @Nullable Drawable createFromStream(@Nullable InputStream is,
+            @Nullable String srcName) {
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
         try {
             return createFromResourceStream(null, null, is, srcName);
@@ -1222,8 +1219,8 @@
      * Create a drawable from an inputstream, using the given resources and
      * value to determine density information.
      */
-    public static Drawable createFromResourceStream(Resources res, TypedValue value,
-            InputStream is, String srcName) {
+    public static @Nullable Drawable createFromResourceStream(@Nullable Resources res,
+            @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName) {
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable");
         try {
             return createFromResourceStream(res, value, is, srcName, null);
@@ -1238,8 +1235,7 @@
      *
      * @deprecated Prefer the version without an Options object.
      */
-    @Nullable
-    public static Drawable createFromResourceStream(@Nullable Resources res,
+    public static @Nullable Drawable createFromResourceStream(@Nullable Resources res,
             @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName,
             @Nullable BitmapFactory.Options opts) {
         if (is == null) {
@@ -1281,7 +1277,8 @@
         return null;
     }
 
-    private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
+    private static Drawable getBitmapDrawable(Resources res, @Nullable TypedValue value,
+            @NonNull InputStream is) {
         try {
             ImageDecoder.Source source = null;
             if (value != null) {
@@ -1369,9 +1366,9 @@
      * a tag in an XML document, tries to create a Drawable from that tag.
      * Returns null if the tag is not a valid drawable.
      */
-    @NonNull
-    public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser,
-            @NonNull AttributeSet attrs) throws XmlPullParserException, IOException {
+    public static @NonNull Drawable createFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs)
+            throws XmlPullParserException, IOException {
         return createFromXmlInner(r, parser, attrs, null);
     }
 
@@ -1381,9 +1378,8 @@
      * document, tries to create a Drawable from that tag. Returns {@code null}
      * if the tag is not a valid drawable.
      */
-    @NonNull
-    public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser,
-            @NonNull AttributeSet attrs, @Nullable Theme theme)
+    public static @NonNull Drawable createFromXmlInner(@NonNull Resources r,
+            @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         return createFromXmlInnerForDensity(r, parser, attrs, 0, theme);
     }
@@ -1392,8 +1388,7 @@
      * Version of {@link #createFromXmlInner(Resources, XmlPullParser, AttributeSet, Theme)} that
      * accepts an override density.
      */
-    @NonNull
-    static Drawable createFromXmlInnerForDensity(@NonNull Resources r,
+    static @NonNull Drawable createFromXmlInnerForDensity(@NonNull Resources r,
             @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density,
             @Nullable Theme theme) throws XmlPullParserException, IOException {
         return r.getDrawableInflater().inflateFromXmlForDensity(parser.getName(), parser, attrs,
@@ -1403,8 +1398,7 @@
     /**
      * Create a drawable from file path name.
      */
-    @Nullable
-    public static Drawable createFromPath(String pathName) {
+    public static @Nullable Drawable createFromPath(String pathName) {
         if (pathName == null) {
             return null;
         }
diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java
index 66752a2..8debe26 100644
--- a/graphics/java/android/graphics/drawable/DrawableInflater.java
+++ b/graphics/java/android/graphics/drawable/DrawableInflater.java
@@ -61,8 +61,7 @@
      * @param id the identifier of the drawable resource
      * @return a drawable, or {@code null} if the drawable failed to load
      */
-    @Nullable
-    public static Drawable loadDrawable(@NonNull Context context, @DrawableRes int id) {
+    public static @Nullable Drawable loadDrawable(@NonNull Context context, @DrawableRes int id) {
         return loadDrawable(context.getResources(), context.getTheme(), id);
     }
 
@@ -74,9 +73,8 @@
      * @param id the identifier of the drawable resource
      * @return a drawable, or {@code null} if the drawable failed to load
      */
-    @Nullable
-    public static Drawable loadDrawable(
-            @NonNull Resources resources, @Nullable Theme theme, @DrawableRes int id) {
+    public static @Nullable Drawable loadDrawable(@NonNull Resources resources,
+            @Nullable Theme theme, @DrawableRes int id) {
         return resources.getDrawable(id, theme);
     }
 
@@ -111,8 +109,7 @@
      * @throws XmlPullParserException
      * @throws IOException
      */
-    @NonNull
-    public Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser,
+    public @NonNull Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         return inflateFromXmlForDensity(name, parser, attrs, 0, theme);
@@ -122,8 +119,7 @@
      * Version of {@link #inflateFromXml(String, XmlPullParser, AttributeSet, Theme)} that accepts
      * an override density.
      */
-    @NonNull
-    Drawable inflateFromXmlForDensity(@NonNull String name, @NonNull XmlPullParser parser,
+    @NonNull Drawable inflateFromXmlForDensity(@NonNull String name, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, int density, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         // Inner classes must be referenced as Outer$Inner, but XML tag names
@@ -146,9 +142,8 @@
         return drawable;
     }
 
-    @NonNull
     @SuppressWarnings("deprecation")
-    private Drawable inflateFromTag(@NonNull String name) {
+    private @Nullable Drawable inflateFromTag(@NonNull String name) {
         switch (name) {
             case "selector":
                 return new StateListDrawable();
@@ -195,8 +190,7 @@
         }
     }
 
-    @NonNull
-    private Drawable inflateFromClass(@NonNull String className) {
+    private @NonNull Drawable inflateFromClass(@NonNull String className) {
         try {
             Constructor<? extends Drawable> constructor;
             synchronized (CONSTRUCTOR_MAP) {
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index ebde757..a63d7f6 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -352,7 +352,7 @@
     }
 
     @Override
-    protected boolean onStateChange(int[] state) {
+    protected boolean onStateChange(@NonNull int[] state) {
         if (mDrawable != null && mDrawable.isStateful()) {
             final boolean changed = mDrawable.setState(state);
             if (changed) {
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index a03931b..b04b826 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -302,7 +302,7 @@
      *                is available. The {@link android.os.Message#obj obj}
      *                property is populated with the Drawable.
      */
-    public void loadDrawableAsync(Context context, Message andThen) {
+    public void loadDrawableAsync(@NonNull Context context, @NonNull Message andThen) {
         if (andThen.getTarget() == null) {
             throw new IllegalArgumentException("callback message must have a target handler");
         }
@@ -320,7 +320,7 @@
      *                 {@link #loadDrawable(Context)} finished
      * @param handler {@link Handler} on which to notify the {@code listener}
      */
-    public void loadDrawableAsync(Context context, final OnDrawableLoadedListener listener,
+    public void loadDrawableAsync(@NonNull Context context, final OnDrawableLoadedListener listener,
             Handler handler) {
         new LoadDrawableTask(context, handler, listener).runAsync();
     }
@@ -335,7 +335,7 @@
      *                to access {@link android.content.res.Resources Resources}, for example.
      * @return A fresh instance of a drawable for this image, yours to keep.
      */
-    public Drawable loadDrawable(Context context) {
+    public @Nullable Drawable loadDrawable(Context context) {
         final Drawable result = loadDrawableInner(context);
         if (result != null && hasTint()) {
             result.mutate();
@@ -415,7 +415,7 @@
         return null;
     }
 
-    private InputStream getUriInputStream(Context context) {
+    private @Nullable InputStream getUriInputStream(Context context) {
         final Uri uri = getUri();
         final String scheme = uri.getScheme();
         if (ContentResolver.SCHEME_CONTENT.equals(scheme)
@@ -496,7 +496,7 @@
      * @param stream The stream on which to serialize the Icon.
      * @hide
      */
-    public void writeToStream(OutputStream stream) throws IOException {
+    public void writeToStream(@NonNull OutputStream stream) throws IOException {
         DataOutputStream dataStream = new DataOutputStream(stream);
 
         dataStream.writeInt(VERSION_STREAM_SERIALIZER);
@@ -532,7 +532,7 @@
      * @param stream The input stream from which to reconstruct the Icon.
      * @hide
      */
-    public static Icon createFromStream(InputStream stream) throws IOException {
+    public static @Nullable Icon createFromStream(@NonNull InputStream stream) throws IOException {
         DataInputStream inputStream = new DataInputStream(stream);
 
         final int version = inputStream.readInt();
@@ -571,7 +571,7 @@
      * @return whether this icon is the same as the another one
      * @hide
      */
-    public boolean sameAs(Icon otherIcon) {
+    public boolean sameAs(@NonNull Icon otherIcon) {
         if (otherIcon == this) {
             return true;
         }
@@ -602,7 +602,7 @@
      *                given resource ID.
      * @param resId ID of the drawable resource
      */
-    public static Icon createWithResource(Context context, @DrawableRes int resId) {
+    public static @NonNull Icon createWithResource(Context context, @DrawableRes int resId) {
         if (context == null) {
             throw new IllegalArgumentException("Context must not be null.");
         }
@@ -617,7 +617,7 @@
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static Icon createWithResource(Resources res, @DrawableRes int resId) {
+    public static @NonNull Icon createWithResource(Resources res, @DrawableRes int resId) {
         if (res == null) {
             throw new IllegalArgumentException("Resource must not be null.");
         }
@@ -632,7 +632,7 @@
      * @param resPackage Name of the package containing the resource in question
      * @param resId ID of the drawable resource
      */
-    public static Icon createWithResource(String resPackage, @DrawableRes int resId) {
+    public static @NonNull Icon createWithResource(String resPackage, @DrawableRes int resId) {
         if (resPackage == null) {
             throw new IllegalArgumentException("Resource package name must not be null.");
         }
@@ -646,7 +646,7 @@
      * Create an Icon pointing to a bitmap in memory.
      * @param bits A valid {@link android.graphics.Bitmap} object
      */
-    public static Icon createWithBitmap(Bitmap bits) {
+    public static @NonNull Icon createWithBitmap(Bitmap bits) {
         if (bits == null) {
             throw new IllegalArgumentException("Bitmap must not be null.");
         }
@@ -660,7 +660,7 @@
      * by {@link AdaptiveIconDrawable}.
      * @param bits A valid {@link android.graphics.Bitmap} object
      */
-    public static Icon createWithAdaptiveBitmap(Bitmap bits) {
+    public static @NonNull Icon createWithAdaptiveBitmap(Bitmap bits) {
         if (bits == null) {
             throw new IllegalArgumentException("Bitmap must not be null.");
         }
@@ -677,7 +677,7 @@
      * @param offset Offset into <code>data</code> at which the bitmap data starts
      * @param length Length of the bitmap data
      */
-    public static Icon createWithData(byte[] data, int offset, int length) {
+    public static @NonNull Icon createWithData(byte[] data, int offset, int length) {
         if (data == null) {
             throw new IllegalArgumentException("Data must not be null.");
         }
@@ -693,7 +693,7 @@
      *
      * @param uri A uri referring to local content:// or file:// image data.
      */
-    public static Icon createWithContentUri(String uri) {
+    public static @NonNull Icon createWithContentUri(String uri) {
         if (uri == null) {
             throw new IllegalArgumentException("Uri must not be null.");
         }
@@ -707,7 +707,7 @@
      *
      * @param uri A uri referring to local content:// or file:// image data.
      */
-    public static Icon createWithContentUri(Uri uri) {
+    public static @NonNull Icon createWithContentUri(Uri uri) {
         if (uri == null) {
             throw new IllegalArgumentException("Uri must not be null.");
         }
@@ -720,8 +720,7 @@
      *
      * @param uri A uri referring to local content:// or file:// image data.
      */
-    @NonNull
-    public static Icon createWithAdaptiveBitmapContentUri(@NonNull String uri) {
+    public static @NonNull Icon createWithAdaptiveBitmapContentUri(@NonNull String uri) {
         if (uri == null) {
             throw new IllegalArgumentException("Uri must not be null.");
         }
@@ -750,7 +749,7 @@
      * @param tint a color, as in {@link Drawable#setTint(int)}
      * @return this same object, for use in chained construction
      */
-    public Icon setTint(@ColorInt int tint) {
+    public @NonNull Icon setTint(@ColorInt int tint) {
         return setTintList(ColorStateList.valueOf(tint));
     }
 
@@ -760,7 +759,7 @@
      * @param tintList as in {@link Drawable#setTintList(ColorStateList)}, null to remove tint
      * @return this same object, for use in chained construction
      */
-    public Icon setTintList(ColorStateList tintList) {
+    public @NonNull Icon setTintList(ColorStateList tintList) {
         mTintList = tintList;
         return this;
     }
@@ -809,7 +808,7 @@
      * @param path A path to a file that contains compressed bitmap data of
      *           a type that {@link android.graphics.BitmapFactory} can decode.
      */
-    public static Icon createWithFilePath(String path) {
+    public static @NonNull Icon createWithFilePath(String path) {
         if (path == null) {
             throw new IllegalArgumentException("Path must not be null.");
         }
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index 53a6731..4461f39 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -126,7 +126,7 @@
     private static final double PI_ROTATE_LEFT = Math.PI * -0.0078125;
 
     RippleShader() {
-        super(SHADER, false);
+        super(SHADER);
     }
 
     public void setShader(Shader shader) {
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more.xml
deleted file mode 100644
index ff57406..0000000
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24">
-    <path
-        android:fillColor="@android:color/system_neutral2_400"
-        android:pathData="M16.59,8.59L12.0,13.17 7.41,8.59 6.0,10.0l6.0,6.0 6.0,-6.0z"/>
-</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_toast_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_toast_layout.xml
deleted file mode 100644
index a309d48..0000000
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_toast_layout.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<!--
-  ~ Copyright (C) 2022 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.
-  -->
-<com.android.wm.shell.compatui.LetterboxEduToastLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:background="@color/compat_controls_background"
-    android:gravity="center"
-    android:paddingVertical="14dp"
-    android:paddingHorizontal="16dp">
-
-    <!-- Adding an extra layer to animate the alpha of the background and content separately. -->
-    <LinearLayout
-        android:id="@+id/letterbox_education_content"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:gravity="center_vertical"
-        android:orientation="horizontal">
-
-        <ImageView
-            android:id="@+id/letterbox_education_icon"
-            android:layout_width="@dimen/letterbox_education_toast_icon_size"
-            android:layout_height="@dimen/letterbox_education_toast_icon_size"/>
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:maxWidth="@dimen/letterbox_education_toast_text_max_width"
-            android:paddingHorizontal="16dp"
-            android:lineSpacingExtra="5sp"
-            android:text="@string/letterbox_education_toast_title"
-            android:textAlignment="viewStart"
-            android:textColor="@color/compat_controls_text"
-            android:textSize="16sp"
-            android:maxLines="1"
-            android:ellipsize="end"/>
-
-        <ImageButton
-            android:id="@+id/letterbox_education_toast_expand"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/letterbox_education_ic_expand_more_ripple"
-            android:background="@android:color/transparent"
-            android:contentDescription="@string/letterbox_education_expand_button_description"/>
-
-    </LinearLayout>
-
-</com.android.wm.shell.compatui.LetterboxEduToastLayout>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index ab2c9b1..40c7647 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -219,18 +219,9 @@
     <!-- The width of the camera compat hint. -->
     <dimen name="camera_compat_hint_width">143dp</dimen>
 
-    <!-- The corner radius of the letterbox education toast. -->
-    <dimen name="letterbox_education_toast_corner_radius">100dp</dimen>
-
     <!-- The corner radius of the letterbox education dialog. -->
     <dimen name="letterbox_education_dialog_corner_radius">28dp</dimen>
 
-    <!-- The margin between the letterbox education toast/dialog and the bottom of the task. -->
-    <dimen name="letterbox_education_margin_bottom">16dp</dimen>
-
-    <!-- The size of the icon in the letterbox education toast. -->
-    <dimen name="letterbox_education_toast_icon_size">24dp</dimen>
-
     <!-- The size of an icon in the letterbox education dialog. -->
     <dimen name="letterbox_education_dialog_icon_size">48dp</dimen>
 
@@ -243,9 +234,6 @@
     <!-- The maximum width of the title and subtitle in the letterbox education dialog. -->
     <dimen name="letterbox_education_dialog_title_max_width">444dp</dimen>
 
-    <!-- The maximum width of the text in the letterbox education toast. -->
-    <dimen name="letterbox_education_toast_text_max_width">398dp</dimen>
-
     <!-- The distance that the letterbox education dialog will move up during appear/dismiss
          animation.  -->
     <dimen name="letterbox_education_dialog_animation_elevation">20dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index a8a9ed7..16a4b52 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -174,9 +174,6 @@
     <!-- The title of the letterbox education dialog. [CHAR LIMIT=NONE] -->
     <string name="letterbox_education_dialog_title">Get the most out of <xliff:g id="app_name" example="YouTube">%s</xliff:g></string>
 
-    <!-- The title of the letterbox education toast. [CHAR LIMIT=60] -->
-    <string name="letterbox_education_toast_title">Rotate your device for a full-screen view</string>
-
     <!-- Description of the rotate screen into portrait action. [CHAR LIMIT=NONE] -->
     <string name="letterbox_education_screen_rotation_portrait_text">Rotate your screen to portrait</string>
 
@@ -192,7 +189,4 @@
     <!-- Button text for dismissing the letterbox education dialog. [CHAR LIMIT=20] -->
     <string name="letterbox_education_got_it">Got it</string>
 
-    <!-- Accessibility description of the letterbox education toast expand to dialog button. [CHAR LIMIT=NONE] -->
-    <string name="letterbox_education_expand_button_description">Expand for more information.</string>
-
 </resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index b310dd6..9a6df23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -18,9 +18,12 @@
 
 import android.view.MotionEvent;
 
+import com.android.wm.shell.common.annotations.ExternalThread;
+
 /**
- * Interface for SysUI to get access to the Back animation related methods.
+ * Interface for external process to get access to the Back animation related methods.
  */
+@ExternalThread
 public interface BackAnimation {
 
     /**
@@ -32,4 +35,11 @@
      * Sets whether the back gesture is past the trigger threshold or not.
      */
     void setTriggerBack(boolean triggerBack);
+
+    /**
+     * Returns a binder that can be passed to an external process to update back animations.
+     */
+    default IBackAnimation createExternalInterface() {
+        return null;
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 229e8ee0..a5140c3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.back;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
 
 import android.animation.Animator;
@@ -26,6 +27,7 @@
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.app.WindowConfiguration;
+import android.content.Context;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.hardware.HardwareBuffer;
@@ -35,16 +37,18 @@
 import android.view.MotionEvent;
 import android.view.SurfaceControl;
 import android.window.BackNavigationInfo;
+import android.window.IOnBackInvokedCallback;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.annotations.ShellMainThread;
 
 /**
  * Controls the window animation run when a user initiates a back gesture.
  */
-public class BackAnimationController {
+public class BackAnimationController implements RemoteCallable<BackAnimationController> {
 
     private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
     public static final boolean IS_ENABLED = SystemProperties
@@ -72,18 +76,26 @@
     private BackNavigationInfo mBackNavigationInfo;
     private final SurfaceControl.Transaction mTransaction;
     private final IActivityTaskManager mActivityTaskManager;
+    private final Context mContext;
+    @Nullable
+    private IOnBackInvokedCallback mBackToLauncherCallback;
 
-    public BackAnimationController(@ShellMainThread ShellExecutor shellExecutor) {
-        this(shellExecutor, new SurfaceControl.Transaction(), ActivityTaskManager.getService());
+    public BackAnimationController(
+            @ShellMainThread ShellExecutor shellExecutor,
+            Context context) {
+        this(shellExecutor, new SurfaceControl.Transaction(), ActivityTaskManager.getService(),
+                context);
     }
 
     @VisibleForTesting
     BackAnimationController(@NonNull ShellExecutor shellExecutor,
             @NonNull SurfaceControl.Transaction transaction,
-            @NonNull IActivityTaskManager activityTaskManager) {
+            @NonNull IActivityTaskManager activityTaskManager,
+            Context context) {
         mShellExecutor = shellExecutor;
         mTransaction = transaction;
         mActivityTaskManager = activityTaskManager;
+        mContext = context;
     }
 
     public BackAnimation getBackAnimationImpl() {
@@ -92,7 +104,27 @@
 
     private final BackAnimation mBackAnimation = new BackAnimationImpl();
 
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mShellExecutor;
+    }
+
     private class BackAnimationImpl implements BackAnimation {
+        private IBackAnimationImpl mBackAnimation;
+
+        @Override
+        public IBackAnimation createExternalInterface() {
+            if (mBackAnimation != null) {
+                mBackAnimation.invalidate();
+            }
+            mBackAnimation = new IBackAnimationImpl(BackAnimationController.this);
+            return mBackAnimation;
+        }
 
         @Override
         public void onBackMotion(MotionEvent event) {
@@ -105,6 +137,48 @@
         }
     }
 
+    private static class IBackAnimationImpl extends IBackAnimation.Stub {
+        private BackAnimationController mController;
+
+        IBackAnimationImpl(BackAnimationController controller) {
+            mController = controller;
+        }
+
+        @Override
+        public void setBackToLauncherCallback(IOnBackInvokedCallback callback) {
+            executeRemoteCallWithTaskPermission(mController, "setBackToLauncherCallback",
+                    (controller) -> mController.setBackToLauncherCallback(callback));
+        }
+
+        @Override
+        public void clearBackToLauncherCallback() {
+            executeRemoteCallWithTaskPermission(mController, "clearBackToLauncherCallback",
+                    (controller) -> mController.clearBackToLauncherCallback());
+        }
+
+        @Override
+        public void onBackToLauncherAnimationFinished() {
+            executeRemoteCallWithTaskPermission(mController, "onBackToLauncherAnimationFinished",
+                    (controller) -> mController.onBackToLauncherAnimationFinished());
+        }
+
+        void invalidate() {
+            mController = null;
+        }
+    }
+
+    private void setBackToLauncherCallback(IOnBackInvokedCallback callback) {
+        mBackToLauncherCallback = callback;
+    }
+
+    private void clearBackToLauncherCallback() {
+        mBackToLauncherCallback = null;
+    }
+
+    private void onBackToLauncherAnimationFinished() {
+        finishAnimation();
+    }
+
     /**
      * Called when a new motion event needs to be transferred to this
      * {@link BackAnimationController}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl
new file mode 100644
index 0000000..6311f87
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/IBackAnimation.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 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.wm.shell.back;
+
+import android.window.IOnBackInvokedCallback;
+
+/**
+ * Interface for Launcher process to register back invocation callbacks.
+ */
+interface IBackAnimation {
+
+    /**
+     * Sets a {@link IOnBackInvokedCallback} to be invoked when
+     * back navigation has type {@link BackNavigationInfo#TYPE_RETURN_TO_HOME}.
+     */
+    void setBackToLauncherCallback(in IOnBackInvokedCallback callback);
+
+    /**
+     * Clears the previously registered {@link IOnBackInvokedCallback}.
+     */
+    void clearBackToLauncherCallback();
+
+    /**
+     * Notifies Shell that the back to launcher animation has fully finished
+     * (including the transition animation that runs after the finger is lifted).
+     *
+     * At this point the top window leash (if one was created) should be ready to be released.
+     * //TODO: Remove once we play the transition animation through shell transitions.
+     */
+    void onBackToLauncherAnimationFinished();
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index a477bd7..7ab6835 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1790,6 +1790,7 @@
 
     /**
      * Changes the expanded state of the stack.
+     * Don't call this directly, call mBubbleData#setExpanded.
      *
      * @param shouldExpand whether the bubble stack should appear expanded
      */
@@ -1836,7 +1837,7 @@
             } else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
                 mManageEduView.hide();
             } else {
-                setExpanded(false);
+                mBubbleData.setExpanded(false);
             }
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 8f4cfb0..4d279bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -49,7 +49,7 @@
 import java.util.function.Predicate;
 
 /**
- * Controls to show/update restart-activity buttons on Tasks based on whether the foreground
+ * Controller to show/update compat UI components on Tasks based on whether the foreground
  * activities are in compatibility mode.
  */
 public class CompatUIController implements OnDisplaysChangedListener,
@@ -228,8 +228,7 @@
         final CompatUIWindowManager compatUIWindowManager =
                 createLayout(context, taskInfo, taskListener);
         mActiveLayouts.put(taskInfo.taskId, compatUIWindowManager);
-        compatUIWindowManager.createLayout(showOnDisplay(taskInfo.displayId),
-                taskInfo.topActivityInSizeCompat, taskInfo.cameraCompatControlState);
+        compatUIWindowManager.createLayout(showOnDisplay(taskInfo.displayId), taskInfo);
     }
 
     @VisibleForTesting
@@ -254,9 +253,7 @@
         if (layout == null) {
             return;
         }
-        layout.updateCompatInfo(taskInfo.configuration, taskListener,
-                showOnDisplay(layout.getDisplayId()), taskInfo.topActivityInSizeCompat,
-                taskInfo.cameraCompatControlState);
+        layout.updateCompatInfo(taskInfo, taskListener, showOnDisplay(layout.getDisplayId()));
     }
 
     private void removeLayout(int taskId) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index 44526b0..9c001a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -20,28 +20,16 @@
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
 import android.annotation.Nullable;
+import android.app.TaskInfo;
 import android.app.TaskInfo.CameraCompatControlState;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.os.Binder;
 import android.util.Log;
-import android.view.IWindow;
 import android.view.LayoutInflater;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.SurfaceSession;
 import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowlessWindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.wm.shell.R;
@@ -50,26 +38,19 @@
 import com.android.wm.shell.common.SyncTransactionQueue;
 
 /**
- * Holds view hierarchy of a root surface and helps to inflate and manage layout for compat
- * controls.
+ * Window manager for the Size Compat restart button and Camera Compat control.
  */
-class CompatUIWindowManager extends WindowlessWindowManager {
+class CompatUIWindowManager extends CompatUIWindowManagerAbstract {
 
-    private static final String TAG = "CompatUIWindowManager";
+    /**
+     * The Compat UI should be the topmost child of the Task in case there can be more than one
+     * child.
+     */
+    private static final int Z_ORDER = Integer.MAX_VALUE;
 
-    private final SyncTransactionQueue mSyncQueue;
     private final CompatUIController.CompatUICallback mCallback;
-    private final int mDisplayId;
-    private final int mTaskId;
-    private final Rect mStableBounds;
 
-    private Context mContext;
-    private Configuration mTaskConfig;
-    private ShellTaskOrganizer.TaskListener mTaskListener;
-    private DisplayLayout mDisplayLayout;
-
-    // Remember the last reported states in case visibility changes due to keyguard or
-    // IME updates.
+    // Remember the last reported states in case visibility changes due to keyguard or IME updates.
     @VisibleForTesting
     boolean mHasSizeCompat;
     @CameraCompatControlState
@@ -82,147 +63,83 @@
 
     @Nullable
     @VisibleForTesting
-    CompatUILayout mCompatUILayout;
-
-    @Nullable
-    private SurfaceControlViewHost mViewHost;
-    @Nullable
-    private SurfaceControl mLeash;
+    CompatUILayout mLayout;
 
     CompatUIWindowManager(Context context, Configuration taskConfig,
             SyncTransactionQueue syncQueue, CompatUIController.CompatUICallback callback,
             int taskId, ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout,
-             boolean hasShownSizeCompatHint, boolean hasShownCameraCompatHint) {
-        super(taskConfig, null /* rootSurface */, null /* hostInputToken */);
-        mContext = context;
-        mSyncQueue = syncQueue;
+            boolean hasShownSizeCompatHint, boolean hasShownCameraCompatHint) {
+        super(context, taskConfig, syncQueue, taskId, taskListener, displayLayout);
         mCallback = callback;
-        mTaskConfig = taskConfig;
-        mDisplayId = mContext.getDisplayId();
-        mTaskId = taskId;
-        mTaskListener = taskListener;
-        mDisplayLayout = displayLayout;
         mShouldShowSizeCompatHint = !hasShownSizeCompatHint;
         mShouldShowCameraCompatHint = !hasShownCameraCompatHint;
-        mStableBounds = new Rect();
-        mDisplayLayout.getStableBounds(mStableBounds);
     }
 
     @Override
-    public void setConfiguration(Configuration configuration) {
-        super.setConfiguration(configuration);
-        mContext = mContext.createConfigurationContext(configuration);
+    protected int getZOrder() {
+        return Z_ORDER;
+    }
+
+
+    @Override
+    protected @Nullable View getLayout() {
+        return mLayout;
     }
 
     @Override
-    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
-        // Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later.
-        final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
-                .setContainerLayer()
-                .setName("CompatUILeash")
-                .setHidden(false)
-                .setCallsite("CompatUIWindowManager#attachToParentSurface");
-        attachToParentSurface(builder);
-        mLeash = builder.build();
-        b.setParent(mLeash);
+    protected void removeLayout() {
+        mLayout = null;
     }
 
-    /** Creates the layout for compat controls. */
-    void createLayout(boolean show, boolean hasSizeCompat,
-            @CameraCompatControlState int cameraCompatControlState) {
-        mHasSizeCompat = hasSizeCompat;
-        mCameraCompatControlState = cameraCompatControlState;
-        if (!show || mCompatUILayout != null) {
-            // Wait until compat controls should be visible.
-            return;
-        }
+    @Override
+    protected boolean eligibleToShowLayout() {
+        return mHasSizeCompat || shouldShowCameraControl();
+    }
 
-        initCompatUi();
-        updateSurfacePosition();
+    /**
+     * Updates the internal state with respect to {@code taskInfo} and calls {@link
+     * #createLayout(boolean)}.
+     */
+    void createLayout(boolean canShow, TaskInfo taskInfo) {
+        mHasSizeCompat = taskInfo.topActivityInSizeCompat;
+        mCameraCompatControlState = taskInfo.cameraCompatControlState;
+        createLayout(canShow);
+    }
 
-        if (hasSizeCompat) {
+    @Override
+    protected View createLayout() {
+        mLayout = inflateLayout();
+        mLayout.inject(this);
+
+        updateVisibilityOfViews();
+
+        if (mHasSizeCompat) {
             mCallback.onSizeCompatRestartButtonAppeared(mTaskId);
         }
+
+        return mLayout;
     }
 
-    private void createLayout(boolean show) {
-        createLayout(show, mHasSizeCompat, mCameraCompatControlState);
+    @VisibleForTesting
+    CompatUILayout inflateLayout() {
+        return (CompatUILayout) LayoutInflater.from(mContext).inflate(R.layout.compat_ui_layout,
+                null);
     }
 
-    /** Called when compat info changed. */
-    void updateCompatInfo(Configuration taskConfig,
-            ShellTaskOrganizer.TaskListener taskListener, boolean show, boolean hasSizeCompat,
-            @CameraCompatControlState int cameraCompatControlState) {
-        final Configuration prevTaskConfig = mTaskConfig;
-        final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener;
-        mTaskConfig = taskConfig;
-        mTaskListener = taskListener;
+    @Override
+    public void updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener,
+            boolean canShow) {
         final boolean prevHasSizeCompat = mHasSizeCompat;
         final int prevCameraCompatControlState = mCameraCompatControlState;
-        mHasSizeCompat = hasSizeCompat;
-        mCameraCompatControlState = cameraCompatControlState;
+        mHasSizeCompat = taskInfo.topActivityInSizeCompat;
+        mCameraCompatControlState = taskInfo.cameraCompatControlState;
 
-        // Update configuration.
-        mContext = mContext.createConfigurationContext(taskConfig);
-        setConfiguration(taskConfig);
-
-        if (mCompatUILayout == null || prevTaskListener != taskListener) {
-            // TaskListener changed, recreate the layout for new surface parent.
-            release();
-            createLayout(show);
-            return;
-        }
+        super.updateCompatInfo(taskInfo, taskListener, canShow);
 
         if (prevHasSizeCompat != mHasSizeCompat
                 || prevCameraCompatControlState != mCameraCompatControlState) {
             updateVisibilityOfViews();
         }
-
-        if (!taskConfig.windowConfiguration.getBounds()
-                .equals(prevTaskConfig.windowConfiguration.getBounds())) {
-            // Reposition the UI surfaces.
-            updateSurfacePosition();
-        }
-
-        if (taskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection()) {
-            // Update layout for RTL.
-            mCompatUILayout.setLayoutDirection(taskConfig.getLayoutDirection());
-            updateSurfacePosition();
-        }
-
-    }
-
-    /** Called when the visibility of the UI should change. */
-    void updateVisibility(boolean show) {
-        if (mCompatUILayout == null) {
-            // Layout may not have been created because it was hidden previously.
-            createLayout(show);
-            return;
-        }
-
-        // Hide compat UIs when IME is showing.
-        final int newVisibility = show ? View.VISIBLE : View.GONE;
-        if (mCompatUILayout.getVisibility() != newVisibility) {
-            mCompatUILayout.setVisibility(newVisibility);
-        }
-    }
-
-    /** Called when display layout changed. */
-    void updateDisplayLayout(DisplayLayout displayLayout) {
-        final Rect prevStableBounds = mStableBounds;
-        final Rect curStableBounds = new Rect();
-        displayLayout.getStableBounds(curStableBounds);
-        mDisplayLayout = displayLayout;
-        if (!prevStableBounds.equals(curStableBounds)) {
-            // Stable bounds changed, update UI surface positions.
-            updateSurfacePosition();
-            mStableBounds.set(curStableBounds);
-        }
-    }
-
-    /** Called when it is ready to be placed compat UI surface. */
-    void attachToParentSurface(SurfaceControl.Builder b) {
-        mTaskListener.attachChildSurfaceToTask(mTaskId, b);
     }
 
     /** Called when the restart button is clicked. */
@@ -233,7 +150,7 @@
     /** Called when the camera treatment button is clicked. */
     void onCameraTreatmentButtonClicked() {
         if (!shouldShowCameraControl()) {
-            Log.w(TAG, "Camera compat shouldn't receive clicks in the hidden state.");
+            Log.w(getTag(), "Camera compat shouldn't receive clicks in the hidden state.");
             return;
         }
         // When a camera control is shown, only two states are allowed: "treament applied" and
@@ -244,141 +161,72 @@
                         ? CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED
                         : CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
         mCallback.onCameraControlStateUpdated(mTaskId, mCameraCompatControlState);
-        mCompatUILayout.updateCameraTreatmentButton(mCameraCompatControlState);
+        mLayout.updateCameraTreatmentButton(mCameraCompatControlState);
     }
 
     /** Called when the camera dismiss button is clicked. */
     void onCameraDismissButtonClicked() {
         if (!shouldShowCameraControl()) {
-            Log.w(TAG, "Camera compat shouldn't receive clicks in the hidden state.");
+            Log.w(getTag(), "Camera compat shouldn't receive clicks in the hidden state.");
             return;
         }
         mCameraCompatControlState = CAMERA_COMPAT_CONTROL_DISMISSED;
         mCallback.onCameraControlStateUpdated(mTaskId, CAMERA_COMPAT_CONTROL_DISMISSED);
-        mCompatUILayout.setCameraControlVisibility(/* show= */ false);
+        mLayout.setCameraControlVisibility(/* show= */ false);
     }
 
     /** Called when the restart button is long clicked. */
     void onRestartButtonLongClicked() {
-        if (mCompatUILayout == null) {
+        if (mLayout == null) {
             return;
         }
-        mCompatUILayout.setSizeCompatHintVisibility(/* show= */ true);
+        mLayout.setSizeCompatHintVisibility(/* show= */ true);
     }
 
     /** Called when either dismiss or treatment camera buttons is long clicked. */
     void onCameraButtonLongClicked() {
-        if (mCompatUILayout == null) {
+        if (mLayout == null) {
             return;
         }
-        mCompatUILayout.setCameraCompatHintVisibility(/* show= */ true);
+        mLayout.setCameraCompatHintVisibility(/* show= */ true);
     }
 
-    int getDisplayId() {
-        return mDisplayId;
-    }
-
-    int getTaskId() {
-        return mTaskId;
-    }
-
-    /** Releases the surface control and tears down the view hierarchy. */
-    void release() {
-        // Hiding before releasing to avoid flickering when transitioning to the Home screen.
-        mCompatUILayout.setVisibility(View.GONE);
-        mCompatUILayout = null;
-
-        if (mViewHost != null) {
-            mViewHost.release();
-            mViewHost = null;
-        }
-
-        if (mLeash != null) {
-            final SurfaceControl leash = mLeash;
-            mSyncQueue.runInSync(t -> t.remove(leash));
-            mLeash = null;
-        }
-    }
-
-    void relayout() {
-        mViewHost.relayout(getWindowLayoutParams());
-        updateSurfacePosition();
-    }
-
-    @VisibleForTesting
-    void updateSurfacePosition() {
-        if (mCompatUILayout == null || mLeash == null) {
+    @Override
+    protected void updateSurfacePosition(Rect taskBounds, Rect stableBounds) {
+        if (mLayout == null) {
             return;
         }
-
-        // Use stable bounds to prevent controls from overlapping with system bars.
-        final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
-        final Rect stableBounds = new Rect();
-        mDisplayLayout.getStableBounds(stableBounds);
-        stableBounds.intersect(taskBounds);
-
         // Position of the button in the container coordinate.
         final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
                 ? stableBounds.left - taskBounds.left
-                : stableBounds.right - taskBounds.left - mCompatUILayout.getMeasuredWidth();
+                : stableBounds.right - taskBounds.left - mLayout.getMeasuredWidth();
         final int positionY = stableBounds.bottom - taskBounds.top
-                - mCompatUILayout.getMeasuredHeight();
+                - mLayout.getMeasuredHeight();
 
         updateSurfacePosition(positionX, positionY);
     }
 
-    private int getLayoutDirection() {
-        return mContext.getResources().getConfiguration().getLayoutDirection();
-    }
-
-    private void updateSurfacePosition(int positionX, int positionY) {
-        mSyncQueue.runInSync(t -> {
-            if (mLeash == null || !mLeash.isValid()) {
-                Log.w(TAG, "The leash has been released.");
-                return;
-            }
-            t.setPosition(mLeash, positionX, positionY);
-            // The compat UI should be the topmost child of the Task in case there can be more
-            // than one children.
-            t.setLayer(mLeash, Integer.MAX_VALUE);
-        });
-    }
-
-    /** Inflates {@link CompatUILayout} on to the root surface. */
-    private void initCompatUi() {
-        if (mViewHost != null) {
-            throw new IllegalStateException(
-                    "A UI has already been created with this window manager.");
-        }
-
-        // Construction extracted into the separate methods to allow injection for tests.
-        mViewHost = createSurfaceViewHost();
-        mCompatUILayout = inflateCompatUILayout();
-        mCompatUILayout.inject(this);
-
-        updateVisibilityOfViews();
-
-        mViewHost.setView(mCompatUILayout, getWindowLayoutParams());
-    }
-
     private void updateVisibilityOfViews() {
+        if (mLayout == null) {
+            return;
+        }
         // Size Compat mode restart button.
-        mCompatUILayout.setRestartButtonVisibility(mHasSizeCompat);
+        mLayout.setRestartButtonVisibility(mHasSizeCompat);
         if (mHasSizeCompat && mShouldShowSizeCompatHint) {
-            mCompatUILayout.setSizeCompatHintVisibility(/* show= */ true);
+            mLayout.setSizeCompatHintVisibility(/* show= */ true);
             // Only show by default for the first time.
             mShouldShowSizeCompatHint = false;
         }
 
         // Camera control for stretched issues.
-        mCompatUILayout.setCameraControlVisibility(shouldShowCameraControl());
+        mLayout.setCameraControlVisibility(shouldShowCameraControl());
         if (shouldShowCameraControl() && mShouldShowCameraCompatHint) {
-            mCompatUILayout.setCameraCompatHintVisibility(/* show= */ true);
+            mLayout.setCameraCompatHintVisibility(/* show= */ true);
             // Only show by default for the first time.
             mShouldShowCameraCompatHint = false;
         }
         if (shouldShowCameraControl()) {
-            mCompatUILayout.updateCameraTreatmentButton(mCameraCompatControlState);
+            mLayout.updateCameraTreatmentButton(mCameraCompatControlState);
         }
     }
 
@@ -386,32 +234,4 @@
         return mCameraCompatControlState != CAMERA_COMPAT_CONTROL_HIDDEN
                 && mCameraCompatControlState != CAMERA_COMPAT_CONTROL_DISMISSED;
     }
-
-    @VisibleForTesting
-    CompatUILayout inflateCompatUILayout() {
-        return (CompatUILayout) LayoutInflater.from(mContext)
-                .inflate(R.layout.compat_ui_layout, null);
-    }
-
-    @VisibleForTesting
-    SurfaceControlViewHost createSurfaceViewHost() {
-        return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
-    }
-
-    /** Gets the layout params. */
-    private WindowManager.LayoutParams getWindowLayoutParams() {
-        // Measure how big the hint is since its size depends on the text size.
-        mCompatUILayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
-        final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
-                // Cannot be wrap_content as this determines the actual window size
-                mCompatUILayout.getMeasuredWidth(), mCompatUILayout.getMeasuredHeight(),
-                TYPE_APPLICATION_OVERLAY,
-                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
-                PixelFormat.TRANSLUCENT);
-        winParams.token = new Binder();
-        winParams.setTitle(CompatUILayout.class.getSimpleName() + mTaskId);
-        winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
-        return winParams;
-    }
-
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
new file mode 100644
index 0000000..b9a9db1
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2022 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.wm.shell.compatui;
+
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import android.annotation.Nullable;
+import android.app.TaskInfo;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.util.Log;
+import android.view.IWindow;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceSession;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+/**
+ * A superclass for all Compat UI {@link WindowlessWindowManager}s that holds shared logic and
+ * exposes general API for {@link CompatUIController}.
+ *
+ * <p>Holds view hierarchy of a root surface and helps to inflate and manage layout.
+ */
+abstract class CompatUIWindowManagerAbstract extends WindowlessWindowManager {
+
+    protected final SyncTransactionQueue mSyncQueue;
+    protected final int mDisplayId;
+    protected final int mTaskId;
+
+    protected Context mContext;
+    protected Configuration mTaskConfig;
+    protected ShellTaskOrganizer.TaskListener mTaskListener;
+    protected DisplayLayout mDisplayLayout;
+    protected final Rect mStableBounds;
+
+    /**
+     * Utility class for adding and releasing a View hierarchy for this {@link
+     * WindowlessWindowManager} to {@code mLeash}.
+     */
+    @Nullable
+    protected SurfaceControlViewHost mViewHost;
+
+    /**
+     * A surface leash to position the layout relative to the task, since we can't set position for
+     * the {@code mViewHost} directly.
+     */
+    @Nullable
+    protected SurfaceControl mLeash;
+
+    protected CompatUIWindowManagerAbstract(Context context, Configuration taskConfig,
+            SyncTransactionQueue syncQueue, int taskId,
+            ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout) {
+        super(taskConfig, null /* rootSurface */, null /* hostInputToken */);
+        mContext = context;
+        mSyncQueue = syncQueue;
+        mTaskConfig = taskConfig;
+        mDisplayId = mContext.getDisplayId();
+        mTaskId = taskId;
+        mTaskListener = taskListener;
+        mDisplayLayout = displayLayout;
+        mStableBounds = new Rect();
+        mDisplayLayout.getStableBounds(mStableBounds);
+    }
+
+    /**
+     * Returns the z-order of this window which will be passed to the {@link SurfaceControl} once
+     * {@link #attachToParentSurface} is called.
+     *
+     * <p>See {@link SurfaceControl.Transaction#setLayer}.
+     */
+    protected abstract int getZOrder();
+
+    /** Returns the layout of this window manager. */
+    protected abstract @Nullable View getLayout();
+
+    /**
+     * Inflates and inits the layout of this window manager on to the root surface if both {@code
+     * canShow} and {@link #eligibleToShowLayout} are true.
+     *
+     * @param canShow whether the layout is allowed to be shown by the parent controller.
+     */
+    void createLayout(boolean canShow) {
+        if (!canShow || !eligibleToShowLayout() || getLayout() != null) {
+            // Wait until layout should be visible.
+            return;
+        }
+
+        if (mViewHost != null) {
+            throw new IllegalStateException(
+                    "A UI has already been created with this window manager.");
+        }
+
+        // Construction extracted into separate methods to allow injection for tests.
+        mViewHost = createSurfaceViewHost();
+        mViewHost.setView(createLayout(), getWindowLayoutParams());
+
+        updateSurfacePosition();
+    }
+
+    /** Inflates and inits the layout of this window manager. */
+    protected abstract View createLayout();
+
+    protected abstract void removeLayout();
+
+    /**
+     * Whether the layout is eligible to be shown according to the internal state of the subclass.
+     * Returns true by default if subclass doesn't override this method.
+     */
+    protected boolean eligibleToShowLayout() {
+        return true;
+    }
+
+    @Override
+    public void setConfiguration(Configuration configuration) {
+        super.setConfiguration(configuration);
+        mContext = mContext.createConfigurationContext(configuration);
+    }
+
+    @Override
+    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+        String className = getClass().getSimpleName();
+        final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
+                .setContainerLayer()
+                .setName(className + "Leash")
+                .setHidden(false)
+                .setCallsite(className + "#attachToParentSurface");
+        attachToParentSurface(builder);
+        mLeash = builder.build();
+        b.setParent(mLeash);
+
+        initSurface(mLeash);
+    }
+
+    /** Inits the z-order of the surface. */
+    private void initSurface(SurfaceControl leash) {
+        final int z = getZOrder();
+        mSyncQueue.runInSync(t -> {
+            if (leash == null || !leash.isValid()) {
+                Log.w(getTag(), "The leash has been released.");
+                return;
+            }
+            t.setLayer(leash, z);
+        });
+    }
+
+    /**
+     * Called when compat info changed.
+     *
+     * @param canShow whether the layout is allowed to be shown by the parent controller.
+     */
+    void updateCompatInfo(TaskInfo taskInfo,
+            ShellTaskOrganizer.TaskListener taskListener, boolean canShow) {
+        final Configuration prevTaskConfig = mTaskConfig;
+        final ShellTaskOrganizer.TaskListener prevTaskListener = mTaskListener;
+        mTaskConfig = taskInfo.configuration;
+        mTaskListener = taskListener;
+
+        // Update configuration.
+        setConfiguration(mTaskConfig);
+
+        View layout = getLayout();
+        if (layout == null || prevTaskListener != taskListener) {
+            // TaskListener changed, recreate the layout for new surface parent.
+            release();
+            createLayout(canShow);
+            return;
+        }
+
+        boolean boundsUpdated = !mTaskConfig.windowConfiguration.getBounds().equals(
+                prevTaskConfig.windowConfiguration.getBounds());
+        boolean layoutDirectionUpdated =
+                mTaskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection();
+        if (boundsUpdated || layoutDirectionUpdated) {
+            // Reposition the UI surfaces.
+            updateSurfacePosition();
+        }
+
+        if (layout != null && layoutDirectionUpdated) {
+            // Update layout for RTL.
+            layout.setLayoutDirection(mTaskConfig.getLayoutDirection());
+        }
+    }
+
+
+    /**
+     * Updates the visibility of the layout.
+     *
+     * @param canShow whether the layout is allowed to be shown by the parent controller.
+     */
+    void updateVisibility(boolean canShow) {
+        View layout = getLayout();
+        if (layout == null) {
+            // Layout may not have been created because it was hidden previously.
+            createLayout(canShow);
+            return;
+        }
+
+        final int newVisibility = canShow && eligibleToShowLayout() ? View.VISIBLE : View.GONE;
+        if (layout.getVisibility() != newVisibility) {
+            layout.setVisibility(newVisibility);
+        }
+    }
+
+    /** Called when display layout changed. */
+    void updateDisplayLayout(DisplayLayout displayLayout) {
+        final Rect prevStableBounds = mStableBounds;
+        final Rect curStableBounds = new Rect();
+        displayLayout.getStableBounds(curStableBounds);
+        mDisplayLayout = displayLayout;
+        if (!prevStableBounds.equals(curStableBounds)) {
+            // Stable bounds changed, update UI surface positions.
+            updateSurfacePosition();
+            mStableBounds.set(curStableBounds);
+        }
+    }
+
+    /** Called when the surface is ready to be placed under the task surface. */
+    @VisibleForTesting
+    void attachToParentSurface(SurfaceControl.Builder b) {
+        mTaskListener.attachChildSurfaceToTask(mTaskId, b);
+    }
+
+    int getDisplayId() {
+        return mDisplayId;
+    }
+
+    int getTaskId() {
+        return mTaskId;
+    }
+
+    /** Releases the surface control and tears down the view hierarchy. */
+    void release() {
+        // Hiding before releasing to avoid flickering when transitioning to the Home screen.
+        View layout = getLayout();
+        if (layout != null) {
+            layout.setVisibility(View.GONE);
+        }
+        removeLayout();
+
+        if (mViewHost != null) {
+            mViewHost.release();
+            mViewHost = null;
+        }
+
+        if (mLeash != null) {
+            final SurfaceControl leash = mLeash;
+            mSyncQueue.runInSync(t -> t.remove(leash));
+            mLeash = null;
+        }
+    }
+
+    /** Re-layouts the view host and updates the surface position. */
+    void relayout() {
+        if (mViewHost == null) {
+            return;
+        }
+        mViewHost.relayout(getWindowLayoutParams());
+        updateSurfacePosition();
+    }
+
+    /**
+     * Updates the position of the surface with respect to the task bounds and display layout
+     * stable bounds.
+     */
+    @VisibleForTesting
+    void updateSurfacePosition() {
+        if (mLeash == null) {
+            return;
+        }
+        // Use stable bounds to prevent controls from overlapping with system bars.
+        final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
+        final Rect stableBounds = new Rect();
+        mDisplayLayout.getStableBounds(stableBounds);
+        stableBounds.intersect(taskBounds);
+
+        updateSurfacePosition(taskBounds, stableBounds);
+    }
+
+    /**
+     * Updates the position of the surface with respect to the given {@code taskBounds} and {@code
+     * stableBounds}.
+     */
+    protected abstract void updateSurfacePosition(Rect taskBounds, Rect stableBounds);
+
+    /**
+     * Updates the position of the surface with respect to the given {@code positionX} and {@code
+     * positionY}.
+     */
+    protected void updateSurfacePosition(int positionX, int positionY) {
+        mSyncQueue.runInSync(t -> {
+            if (mLeash == null || !mLeash.isValid()) {
+                Log.w(getTag(), "The leash has been released.");
+                return;
+            }
+            t.setPosition(mLeash, positionX, positionY);
+        });
+    }
+
+    protected int getLayoutDirection() {
+        return mContext.getResources().getConfiguration().getLayoutDirection();
+    }
+
+    @VisibleForTesting
+    SurfaceControlViewHost createSurfaceViewHost() {
+        return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+    }
+
+    /** Gets the layout params. */
+    private WindowManager.LayoutParams getWindowLayoutParams() {
+        View layout = getLayout();
+        if (layout == null) {
+            return new WindowManager.LayoutParams();
+        }
+        // Measure how big the hint is since its size depends on the text size.
+        layout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+        return getWindowLayoutParams(layout.getMeasuredWidth(), layout.getMeasuredHeight());
+    }
+
+    /** Gets the layout params given the width and height of the layout. */
+    private WindowManager.LayoutParams getWindowLayoutParams(int width, int height) {
+        final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
+                // Cannot be wrap_content as this determines the actual window size
+                width, height,
+                TYPE_APPLICATION_OVERLAY,
+                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
+                PixelFormat.TRANSLUCENT);
+        winParams.token = new Binder();
+        winParams.setTitle(getClass().getSimpleName() + mTaskId);
+        winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+        return winParams;
+    }
+
+    protected final String getTag() {
+        return getClass().getSimpleName();
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduToastLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduToastLayout.java
deleted file mode 100644
index e7f592d..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduToastLayout.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm.shell.compatui.letterboxedu;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.wm.shell.R;
-
-/**
- * Container for the Letterbox Education Toast.
- */
-// TODO(b/215316431): Add tests
-public class LetterboxEduToastLayout extends FrameLayout {
-
-    public LetterboxEduToastLayout(Context context) {
-        this(context, null);
-    }
-
-    public LetterboxEduToastLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public LetterboxEduToastLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public LetterboxEduToastLayout(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    /**
-     * Register a callback for the dismiss button.
-     * @param callback The callback to register
-     */
-    void setExpandOnClickListener(Runnable callback) {
-        findViewById(R.id.letterbox_education_toast_expand).setOnClickListener(
-                view -> callback.run());
-    }
-
-    /**
-     * Updates the layout with the given app info.
-     * @param appName The name of the app
-     * @param appIcon The icon of the app
-     */
-    void updateAppInfo(String appName, Drawable appIcon) {
-        ImageView icon = findViewById(R.id.letterbox_education_icon);
-        icon.setContentDescription(appName);
-        icon.setImageDrawable(appIcon);
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 9f4ff7c..2e54c79 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -696,11 +696,12 @@
     @WMSingleton
     @Provides
     static Optional<BackAnimationController> provideBackAnimationController(
+            Context context,
             @ShellMainThread ShellExecutor shellExecutor
     ) {
         if (BackAnimationController.IS_ENABLED) {
             return Optional.of(
-                    new BackAnimationController(shellExecutor));
+                    new BackAnimationController(shellExecutor, context));
         }
         return Optional.empty();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 72ead00..32861b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -103,7 +103,7 @@
         };
         context.registerReceiverForAllUsers(closeSystemDialogsBroadcastReceiver,
                 new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), null /* permission */,
-                mainHandler);
+                mainHandler, Context.RECEIVER_EXPORTED);
 
         pipMediaController.addActionListener(this::onMediaActionsChanged);
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index 574a9f4..556742e 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -26,8 +26,16 @@
         <option name="shell-timeout" value="6600s" />
         <option name="test-timeout" value="6000s" />
         <option name="hidden-api-checks" value="false" />
+        <option name="device-listeners"
+                value="com.android.server.wm.flicker.TraceFileReadyListener" />
     </test>
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="(\w)+\.winscope" />
+        <option name="pull-pattern-keys" value="(\w)+\.mp4" />
+        <option name="collect-on-run-ended-only" value="false" />
+        <option name="clean-up" value="true" />
+    </metrics_collector>
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
         <option name="directory-keys" value="/sdcard/flicker" />
         <option name="collect-on-run-ended-only" value="true" />
         <option name="clean-up" value="true" />
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 6524182..9061239 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -93,7 +93,7 @@
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                     .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
-                            repetitions = 20)
+                            repetitions = 5)
         }
     }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 960c7ac..21ced0d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -23,6 +23,7 @@
 
 import android.app.IActivityTaskManager;
 import android.app.WindowConfiguration;
+import android.content.Context;
 import android.hardware.HardwareBuffer;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
@@ -52,6 +53,9 @@
     private final ShellExecutor mShellExecutor = new TestShellExecutor();
 
     @Mock
+    private Context mContext;
+
+    @Mock
     private SurfaceControl.Transaction mTransaction;
 
     @Mock
@@ -63,7 +67,7 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mController = new BackAnimationController(
-                mShellExecutor, mTransaction, mActivityTaskManager);
+                mShellExecutor, mTransaction, mActivityTaskManager, mContext);
     }
 
     private void createNavigationInfo(SurfaceControl topWindowLeash,
@@ -75,7 +79,8 @@
                 screenshotSurface,
                 hardwareBuffer,
                 new WindowConfiguration(),
-                new RemoteCallback((bundle) -> {}));
+                new RemoteCallback((bundle) -> {}),
+                null);
         try {
             doReturn(navigationInfo).when(mActivityTaskManager).startBackNavigation();
         } catch (RemoteException ex) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 4352fd3..741da3f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -116,35 +116,17 @@
         TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, true /* hasSizeCompat */,
                 CAMERA_COMPAT_CONTROL_HIDDEN);
 
-        // Verify that the restart button is added with non-null size compat info.
+        // Verify that the compat controls are added with non-null size compat info.
         mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
 
         verify(mController).createLayout(any(), eq(taskInfo), eq(mMockTaskListener));
 
-        // Verify that the restart button is updated with non-null new size compat info.
-        mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
-                true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN),
-                mMockTaskListener);
-
-        verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener,
-                true /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
-
-        // Verify that the restart button is updated with new camera state.
-        mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
-                true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED),
-                mMockTaskListener);
-
-        verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener,
-                true /* show */, true /* hasSizeCompat */,
+        // Verify that the compat controls are updated with non-null new size compat info.
+        taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, true /* hasSizeCompat */,
                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
+        mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
 
-        mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
-                true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED),
-                mMockTaskListener);
-
-        verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener,
-                true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, true /* canShow */);
 
         // Verify that compat controls are removed with null compat info.
         mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
@@ -155,7 +137,7 @@
 
         clearInvocations(mMockLayout);
         clearInvocations(mController);
-        // Verify that compat controls are removed with dismissed camera state.
+        // Verify that compat controls are removed with no size compat and dismissed camera state.
         taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID,
                 true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
 
@@ -245,11 +227,11 @@
         verify(mMockLayout).updateVisibility(false);
 
         // Verify button remains hidden while IME is showing.
-        mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
-                true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
+        TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_HIDDEN);
+        mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
 
-        verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener,
-                false /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, false /* canShow */);
 
         // Verify button is shown after IME is hidden.
         mController.onImeVisibilityChanged(DISPLAY_ID, false /* isShowing */);
@@ -268,11 +250,11 @@
         verify(mMockLayout).updateVisibility(false);
 
         // Verify button remains hidden while keyguard is occluded.
-        mController.onCompatInfoChanged(createTaskInfo(DISPLAY_ID, TASK_ID,
-                true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN), mMockTaskListener);
+        TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_HIDDEN);
+        mController.onCompatInfoChanged(taskInfo, mMockTaskListener);
 
-        verify(mMockLayout).updateCompatInfo(new Configuration(), mMockTaskListener,
-                false /* show */,  true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        verify(mMockLayout).updateCompatInfo(taskInfo, mMockTaskListener, false /* canShow */);
 
         // Verify button is shown after keyguard becomes not occluded.
         mController.onKeyguardOccludedChanged(false);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
index 353d8fe..2117817 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUILayoutTest.java
@@ -27,6 +27,9 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.app.TaskInfo.CameraCompatControlState;
 import android.content.res.Configuration;
 import android.testing.AndroidTestingRunner;
 import android.view.LayoutInflater;
@@ -83,7 +86,7 @@
         spyOn(mWindowManager);
         spyOn(mCompatUILayout);
         doReturn(mViewHost).when(mWindowManager).createSurfaceViewHost();
-        doReturn(mCompatUILayout).when(mWindowManager).inflateCompatUILayout();
+        doReturn(mCompatUILayout).when(mWindowManager).inflateLayout();
     }
 
     @Test
@@ -107,8 +110,8 @@
 
     @Test
     public void testOnClickForSizeCompatHint() {
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.createLayout(true /* show */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_HIDDEN));
         final LinearLayout sizeCompatHint = mCompatUILayout.findViewById(R.id.size_compat_hint);
         sizeCompatHint.performClick();
 
@@ -117,8 +120,8 @@
 
     @Test
     public void testUpdateCameraTreatmentButton_treatmentAppliedByDefault() {
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
+        mWindowManager.createLayout(true /* show */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED));
         final ImageButton button =
                 mCompatUILayout.findViewById(R.id.camera_compat_treatment_button);
         button.performClick();
@@ -135,8 +138,8 @@
 
     @Test
     public void testUpdateCameraTreatmentButton_treatmentSuggestedByDefault() {
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.createLayout(true /* show */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED));
         final ImageButton button =
                 mCompatUILayout.findViewById(R.id.camera_compat_treatment_button);
         button.performClick();
@@ -153,8 +156,8 @@
 
     @Test
     public void testOnCameraDismissButtonClicked() {
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.createLayout(true /* show */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED));
         final ImageButton button =
                 mCompatUILayout.findViewById(R.id.camera_compat_dismiss_button);
         button.performClick();
@@ -188,11 +191,19 @@
 
     @Test
     public void testOnClickForCameraCompatHint() {
-        mWindowManager.createLayout(true /* show */, false /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.createLayout(true /* show */, createTaskInfo(false /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED));
         final LinearLayout hint = mCompatUILayout.findViewById(R.id.camera_compat_hint);
         hint.performClick();
 
         verify(mCompatUILayout).setCameraCompatHintVisibility(/* show= */ false);
     }
+
+    private static TaskInfo createTaskInfo(boolean hasSizeCompat,
+            @CameraCompatControlState int cameraCompatControlState) {
+        ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+        taskInfo.topActivityInSizeCompat = hasSizeCompat;
+        taskInfo.cameraCompatControlState = cameraCompatControlState;
+        return taskInfo;
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index 11c7973..de882ea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -26,8 +26,8 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -35,6 +35,8 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.app.ActivityManager;
+import android.app.TaskInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
@@ -75,47 +77,45 @@
     @Mock private ShellTaskOrganizer.TaskListener mTaskListener;
     @Mock private CompatUILayout mCompatUILayout;
     @Mock private SurfaceControlViewHost mViewHost;
-    private Configuration mTaskConfig;
 
     private CompatUIWindowManager mWindowManager;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mTaskConfig = new Configuration();
 
         mWindowManager = new CompatUIWindowManager(mContext, new Configuration(),
                 mSyncTransactionQueue, mCallback, TASK_ID, mTaskListener, new DisplayLayout(),
                 false /* hasShownSizeCompatHint */, false /* hasShownSizeCompatHint */);
 
         spyOn(mWindowManager);
-        doReturn(mCompatUILayout).when(mWindowManager).inflateCompatUILayout();
+        doReturn(mCompatUILayout).when(mWindowManager).inflateLayout();
         doReturn(mViewHost).when(mWindowManager).createSurfaceViewHost();
     }
 
     @Test
     public void testCreateSizeCompatButton() {
         // Not create layout if show is false.
-        mWindowManager.createLayout(false /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.createLayout(false /* canShow */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_HIDDEN));
 
-        verify(mWindowManager, never()).inflateCompatUILayout();
+        verify(mWindowManager, never()).inflateLayout();
 
         // Not create hint popup.
         mWindowManager.mShouldShowSizeCompatHint = false;
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_HIDDEN));
 
-        verify(mWindowManager).inflateCompatUILayout();
+        verify(mWindowManager).inflateLayout();
         verify(mCompatUILayout, never()).setSizeCompatHintVisibility(true /* show */);
 
         // Create hint popup.
         mWindowManager.release();
         mWindowManager.mShouldShowSizeCompatHint = true;
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_HIDDEN));
 
-        verify(mWindowManager, times(2)).inflateCompatUILayout();
+        verify(mWindowManager, times(2)).inflateLayout();
         assertNotNull(mCompatUILayout);
         verify(mCompatUILayout).setSizeCompatHintVisibility(true /* show */);
         assertFalse(mWindowManager.mShouldShowSizeCompatHint);
@@ -123,10 +123,10 @@
 
     @Test
     public void testRelease() {
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_HIDDEN));
 
-        verify(mWindowManager).inflateCompatUILayout();
+        verify(mWindowManager).inflateLayout();
 
         mWindowManager.release();
 
@@ -135,65 +135,104 @@
 
     @Test
     public void testUpdateCompatInfo() {
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_HIDDEN);
+        TaskInfo taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.createLayout(true /* canShow */, taskInfo);
 
         // No diff
         clearInvocations(mWindowManager);
-        mWindowManager.updateCompatInfo(mTaskConfig, mTaskListener, true /* show */,
-                true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.updateCompatInfo(taskInfo, mTaskListener, true /* canShow */);
 
         verify(mWindowManager, never()).updateSurfacePosition();
         verify(mWindowManager, never()).release();
-        verify(mWindowManager, never()).createLayout(anyBoolean(), anyBoolean(), anyInt());
+        verify(mWindowManager, never()).createLayout(anyBoolean());
 
         // Change task listener, recreate button.
         clearInvocations(mWindowManager);
         final ShellTaskOrganizer.TaskListener newTaskListener = mock(
                 ShellTaskOrganizer.TaskListener.class);
-        mWindowManager.updateCompatInfo(mTaskConfig, newTaskListener,
-                true /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */);
 
         verify(mWindowManager).release();
-        verify(mWindowManager).createLayout(anyBoolean(), anyBoolean(), anyInt());
+        verify(mWindowManager).createLayout(true);
+
+        // Change in Size Compat to false, hides restart button.
+        clearInvocations(mWindowManager);
+        taskInfo = createTaskInfo(false /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */);
+
+        verify(mCompatUILayout).setRestartButtonVisibility(/* show */ false);
+
+        // Change in Size Compat to true, shows restart button.
+        clearInvocations(mWindowManager);
+        clearInvocations(mCompatUILayout);
+        taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */);
+
+        verify(mCompatUILayout).setRestartButtonVisibility(/* show */ true);
 
         // Change Camera Compat state, show a control.
-        mWindowManager.updateCompatInfo(mTaskConfig, newTaskListener, true /* show */,
-                true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
+        clearInvocations(mWindowManager);
+        clearInvocations(mCompatUILayout);
+        taskInfo = createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
+        mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */);
 
         verify(mCompatUILayout).setCameraControlVisibility(/* show */ true);
         verify(mCompatUILayout).updateCameraTreatmentButton(
                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
 
+        // Change Camera Compat state, update a control.
         clearInvocations(mWindowManager);
         clearInvocations(mCompatUILayout);
-        // Change Camera Compat state, update a control.
-        mWindowManager.updateCompatInfo(mTaskConfig, newTaskListener, true /* show */,
-                true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        taskInfo = createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */);
 
         verify(mCompatUILayout).setCameraControlVisibility(/* show */ true);
         verify(mCompatUILayout).updateCameraTreatmentButton(
                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
 
+        // Change Camera Compat state to hidden, hide a control.
         clearInvocations(mWindowManager);
         clearInvocations(mCompatUILayout);
-        // Change Camera Compat state to hidden, hide a control.
-        mWindowManager.updateCompatInfo(mTaskConfig, newTaskListener,
-                true /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */);
 
         verify(mCompatUILayout).setCameraControlVisibility(/* show */ false);
 
         // Change task bounds, update position.
         clearInvocations(mWindowManager);
-        final Configuration newTaskConfiguration = new Configuration();
-        newTaskConfiguration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000));
-        mWindowManager.updateCompatInfo(newTaskConfiguration, newTaskListener,
-                true /* show */, true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        taskInfo.configuration.windowConfiguration.setBounds(new Rect(0, 1000, 0, 2000));
+        mWindowManager.updateCompatInfo(taskInfo, newTaskListener, true /* canShow */);
 
         verify(mWindowManager).updateSurfacePosition();
     }
 
     @Test
+    public void testUpdateCompatInfoLayoutNotInflatedYet() {
+        TaskInfo taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.createLayout(false /* canShow */, taskInfo);
+
+        verify(mWindowManager, never()).inflateLayout();
+
+        // Change topActivityInSizeCompat to false and pass canShow true, layout shouldn't be
+        // inflated
+        clearInvocations(mWindowManager);
+        taskInfo = createTaskInfo(false /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.updateCompatInfo(taskInfo, mTaskListener, true /* canShow */);
+
+        verify(mWindowManager, never()).inflateLayout();
+
+        // Change topActivityInSizeCompat to true and pass canShow true, layout should be inflated.
+        clearInvocations(mWindowManager);
+        taskInfo = createTaskInfo(true /* hasSizeCompat */, CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.updateCompatInfo(taskInfo, mTaskListener, true /* canShow */);
+
+        verify(mWindowManager).inflateLayout();
+    }
+
+    @Test
     public void testUpdateDisplayLayout() {
         final DisplayInfo displayInfo = new DisplayInfo();
         displayInfo.logicalWidth = 1000;
@@ -237,26 +276,25 @@
     @Test
     public void testUpdateVisibility() {
         // Create button if it is not created.
-        mWindowManager.mCompatUILayout = null;
+        mWindowManager.mLayout = null;
         mWindowManager.mHasSizeCompat = true;
-        mWindowManager.updateVisibility(true /* show */);
+        mWindowManager.updateVisibility(true /* canShow */);
 
-        verify(mWindowManager).createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_HIDDEN);
+        verify(mWindowManager).createLayout(true /* canShow */);
 
         // Hide button.
         clearInvocations(mWindowManager);
         doReturn(View.VISIBLE).when(mCompatUILayout).getVisibility();
-        mWindowManager.updateVisibility(false /* show */);
+        mWindowManager.updateVisibility(false /* canShow */);
 
-        verify(mWindowManager, never()).createLayout(anyBoolean(), anyBoolean(), anyInt());
+        verify(mWindowManager, never()).createLayout(anyBoolean(), any());
         verify(mCompatUILayout).setVisibility(View.GONE);
 
         // Show button.
         doReturn(View.GONE).when(mCompatUILayout).getVisibility();
-        mWindowManager.updateVisibility(true /* show */);
+        mWindowManager.updateVisibility(true /* canShow */);
 
-        verify(mWindowManager, never()).createLayout(anyBoolean(), anyBoolean(), anyInt());
+        verify(mWindowManager, never()).createLayout(anyBoolean(), any());
         verify(mCompatUILayout).setVisibility(View.VISIBLE);
     }
 
@@ -270,8 +308,8 @@
 
     @Test
     public void testOnCameraDismissButtonClicked() {
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED));
         clearInvocations(mCompatUILayout);
         mWindowManager.onCameraDismissButtonClicked();
 
@@ -281,8 +319,8 @@
 
     @Test
     public void testOnCameraTreatmentButtonClicked() {
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED));
         clearInvocations(mCompatUILayout);
         mWindowManager.onCameraTreatmentButtonClicked();
 
@@ -310,10 +348,10 @@
     public void testOnRestartButtonLongClicked_showHint() {
        // Not create hint popup.
         mWindowManager.mShouldShowSizeCompatHint = false;
-        mWindowManager.createLayout(true /* show */, true /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_HIDDEN);
+        mWindowManager.createLayout(true /* canShow */, createTaskInfo(true /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_HIDDEN));
 
-        verify(mWindowManager).inflateCompatUILayout();
+        verify(mWindowManager).inflateLayout();
         verify(mCompatUILayout, never()).setSizeCompatHintVisibility(true /* show */);
 
         mWindowManager.onRestartButtonLongClicked();
@@ -325,10 +363,10 @@
     public void testOnCamerControlLongClicked_showHint() {
        // Not create hint popup.
         mWindowManager.mShouldShowCameraCompatHint = false;
-        mWindowManager.createLayout(true /* show */, false /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.createLayout(true /* canShow */, createTaskInfo(false /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED));
 
-        verify(mWindowManager).inflateCompatUILayout();
+        verify(mWindowManager).inflateLayout();
         verify(mCompatUILayout, never()).setCameraCompatHintVisibility(true /* show */);
 
         mWindowManager.onCameraButtonLongClicked();
@@ -339,30 +377,37 @@
     @Test
     public void testCreateCameraCompatControl() {
         // Not create layout if show is false.
-        mWindowManager.createLayout(false /* show */, false /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.createLayout(false /* canShow */, createTaskInfo(false /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED));
 
-        verify(mWindowManager, never()).inflateCompatUILayout();
+        verify(mWindowManager, never()).inflateLayout();
 
         // Not create hint popup.
         mWindowManager.mShouldShowCameraCompatHint = false;
-        mWindowManager.createLayout(true /* show */, false /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.createLayout(true /* canShow */, createTaskInfo(false /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED));
 
-        verify(mWindowManager).inflateCompatUILayout();
+        verify(mWindowManager).inflateLayout();
         verify(mCompatUILayout, never()).setCameraCompatHintVisibility(true /* show */);
         verify(mCompatUILayout).setCameraControlVisibility(true /* show */);
 
         // Create hint popup.
         mWindowManager.release();
         mWindowManager.mShouldShowCameraCompatHint = true;
-        mWindowManager.createLayout(true /* show */, false /* hasSizeCompat */,
-                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
+        mWindowManager.createLayout(true /* canShow */, createTaskInfo(false /* hasSizeCompat */,
+                CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED));
 
-        verify(mWindowManager, times(2)).inflateCompatUILayout();
+        verify(mWindowManager, times(2)).inflateLayout();
         assertNotNull(mCompatUILayout);
         verify(mCompatUILayout, times(2)).setCameraControlVisibility(true /* show */);
         assertFalse(mWindowManager.mShouldShowCameraCompatHint);
     }
 
+    private static TaskInfo createTaskInfo(boolean hasSizeCompat,
+            @TaskInfo.CameraCompatControlState int cameraCompatControlState) {
+        ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+        taskInfo.topActivityInSizeCompat = hasSizeCompat;
+        taskInfo.cameraCompatControlState = cameraCompatControlState;
+        return taskInfo;
+    }
 }
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index dc31bdd..f6ad4c2 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -345,6 +345,7 @@
         "jni/PathEffect.cpp",
         "jni/PathMeasure.cpp",
         "jni/Picture.cpp",
+        "jni/Region.cpp",
         "jni/Shader.cpp",
         "jni/RenderEffect.cpp",
         "jni/Typeface.cpp",
@@ -394,7 +395,6 @@
                 "jni/GraphicsStatsService.cpp",
                 "jni/Movie.cpp",
                 "jni/MovieImpl.cpp",
-                "jni/Region.cpp", // requires libbinder_ndk
                 "jni/pdf/PdfDocument.cpp",
                 "jni/pdf/PdfEditor.cpp",
                 "jni/pdf/PdfRenderer.cpp",
diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp
index dca10e2..942c050 100644
--- a/libs/hwui/apex/LayoutlibLoader.cpp
+++ b/libs/hwui/apex/LayoutlibLoader.cpp
@@ -14,31 +14,22 @@
  * limitations under the License.
  */
 
-#include "graphics_jni_helpers.h"
-
 #include <GraphicsJNI.h>
 #include <SkGraphics.h>
 
-#include <sstream>
-#include <iostream>
-#include <unicode/putil.h>
 #include <unordered_map>
 #include <vector>
 
+#include "Properties.h"
+#include "android/graphics/jni_runtime.h"
+#include "graphics_jni_helpers.h"
+
 using namespace std;
 
-/*
- * This is responsible for setting up the JNI environment for communication between
- * the Java and native parts of layoutlib, including registering native methods.
- * This is mostly achieved by copying the way it is done in the platform
- * (see AndroidRuntime.cpp).
- */
-
-static JavaVM* javaVM;
-
 extern int register_android_graphics_Bitmap(JNIEnv*);
 extern int register_android_graphics_BitmapFactory(JNIEnv*);
 extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env);
+extern int register_android_graphics_Camera(JNIEnv* env);
 extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
 extern int register_android_graphics_Graphics(JNIEnv* env);
 extern int register_android_graphics_ImageDecoder(JNIEnv*);
@@ -49,10 +40,12 @@
 extern int register_android_graphics_Shader(JNIEnv* env);
 extern int register_android_graphics_RenderEffect(JNIEnv* env);
 extern int register_android_graphics_Typeface(JNIEnv* env);
+extern int register_android_graphics_YuvImage(JNIEnv* env);
 
 namespace android {
 
 extern int register_android_graphics_Canvas(JNIEnv* env);
+extern int register_android_graphics_CanvasProperty(JNIEnv* env);
 extern int register_android_graphics_ColorFilter(JNIEnv* env);
 extern int register_android_graphics_ColorSpace(JNIEnv* env);
 extern int register_android_graphics_DrawFilter(JNIEnv* env);
@@ -62,7 +55,7 @@
 extern int register_android_graphics_Path(JNIEnv* env);
 extern int register_android_graphics_PathMeasure(JNIEnv* env);
 extern int register_android_graphics_Picture(JNIEnv* env);
-//extern int register_android_graphics_Region(JNIEnv* env);
+extern int register_android_graphics_Region(JNIEnv* env);
 extern int register_android_graphics_animation_NativeInterpolatorFactory(JNIEnv* env);
 extern int register_android_graphics_animation_RenderNodeAnimator(JNIEnv* env);
 extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
@@ -71,9 +64,11 @@
 extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
 extern int register_android_graphics_text_LineBreaker(JNIEnv* env);
 extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
+extern int register_android_graphics_text_TextShaper(JNIEnv* env);
+
 extern int register_android_util_PathParser(JNIEnv* env);
-extern int register_android_view_RenderNode(JNIEnv* env);
 extern int register_android_view_DisplayListCanvas(JNIEnv* env);
+extern int register_android_view_RenderNode(JNIEnv* env);
 
 #define REG_JNI(name)      { name }
 struct RegJNIRec {
@@ -87,8 +82,9 @@
         {"android.graphics.BitmapFactory", REG_JNI(register_android_graphics_BitmapFactory)},
         {"android.graphics.ByteBufferStreamAdaptor",
          REG_JNI(register_android_graphics_ByteBufferStreamAdaptor)},
+        {"android.graphics.Camera", REG_JNI(register_android_graphics_Camera)},
         {"android.graphics.Canvas", REG_JNI(register_android_graphics_Canvas)},
-        {"android.graphics.RenderNode", REG_JNI(register_android_view_RenderNode)},
+        {"android.graphics.CanvasProperty", REG_JNI(register_android_graphics_CanvasProperty)},
         {"android.graphics.ColorFilter", REG_JNI(register_android_graphics_ColorFilter)},
         {"android.graphics.ColorSpace", REG_JNI(register_android_graphics_ColorSpace)},
         {"android.graphics.CreateJavaOutputStreamAdaptor",
@@ -107,10 +103,12 @@
         {"android.graphics.PathMeasure", REG_JNI(register_android_graphics_PathMeasure)},
         {"android.graphics.Picture", REG_JNI(register_android_graphics_Picture)},
         {"android.graphics.RecordingCanvas", REG_JNI(register_android_view_DisplayListCanvas)},
-//        {"android.graphics.Region", REG_JNI(register_android_graphics_Region)},
+        {"android.graphics.Region", REG_JNI(register_android_graphics_Region)},
+        {"android.graphics.RenderNode", REG_JNI(register_android_view_RenderNode)},
         {"android.graphics.Shader", REG_JNI(register_android_graphics_Shader)},
         {"android.graphics.RenderEffect", REG_JNI(register_android_graphics_RenderEffect)},
         {"android.graphics.Typeface", REG_JNI(register_android_graphics_Typeface)},
+        {"android.graphics.YuvImage", REG_JNI(register_android_graphics_YuvImage)},
         {"android.graphics.animation.NativeInterpolatorFactory",
          REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory)},
         {"android.graphics.animation.RenderNodeAnimator",
@@ -124,6 +122,7 @@
         {"android.graphics.text.LineBreaker", REG_JNI(register_android_graphics_text_LineBreaker)},
         {"android.graphics.text.MeasuredText",
          REG_JNI(register_android_graphics_text_MeasuredText)},
+        {"android.graphics.text.TextRunShaper", REG_JNI(register_android_graphics_text_TextShaper)},
         {"android.util.PathParser", REG_JNI(register_android_util_PathParser)},
 };
 
@@ -177,10 +176,9 @@
                                                          "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
 
     // Get the names of classes that need to register their native methods
-    auto nativesClassesJString =
-            (jstring) env->CallStaticObjectMethod(system,
-                                                  getPropertyMethod, env->NewStringUTF("native_classes"),
-                                                  env->NewStringUTF(""));
+    auto nativesClassesJString = (jstring)env->CallStaticObjectMethod(
+            system, getPropertyMethod, env->NewStringUTF("graphics_native_classes"),
+            env->NewStringUTF(""));
     vector<string> classesToRegister = parseCsv(env, nativesClassesJString);
 
     if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) {
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index c505b53..899c7d4 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -261,11 +261,10 @@
     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete));
 }
 
-static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr,
-                                  jboolean isOpaque) {
+static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) {
     SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder);
     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
-    sk_sp<SkShader> shader = builder->makeShader(matrix, isOpaque == JNI_TRUE);
+    sk_sp<SkShader> shader = builder->makeShader(matrix, false);
     ThrowIAE_IfNull(env, shader);
     return reinterpret_cast<jlong>(shader.release());
 }
@@ -419,7 +418,7 @@
 
 static const JNINativeMethod gRuntimeShaderMethods[] = {
         {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer},
-        {"nativeCreateShader", "(JJZ)J", (void*)RuntimeShader_create},
+        {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create},
         {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder},
         {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V",
          (void*)RuntimeShader_updateFloatArrayUniforms},
diff --git a/media/Android.bp b/media/Android.bp
index fcdfd72..5aedcfb 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -108,6 +108,11 @@
             vndk: {
                 enabled: true,
             },
+            min_sdk_version: "29",
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.bluetooth",
+            ],
         },
     },
 }
diff --git a/media/java/android/media/AudioDescriptor.java b/media/java/android/media/AudioDescriptor.java
index 11371b1..df648be 100644
--- a/media/java/android/media/AudioDescriptor.java
+++ b/media/java/android/media/AudioDescriptor.java
@@ -18,16 +18,21 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * The AudioDescriptor contains the information to describe the audio playback/capture
  * capabilities. The capabilities are described by a byte array, which is defined by a
  * particular standard. This is used when the format is unrecognized to the platform.
  */
-public class AudioDescriptor {
+public class AudioDescriptor implements Parcelable {
     /**
      * The audio standard is not specified.
      */
@@ -49,7 +54,15 @@
     private final byte[] mDescriptor;
     private final int mEncapsulationType;
 
-    AudioDescriptor(int standard, int encapsulationType, @NonNull byte[] descriptor) {
+    /**
+     * @hide
+     * Constructor from standard, encapsulation type and descriptor
+     * @param standard the standard of the audio descriptor
+     * @param encapsulationType the encapsulation type of the audio descriptor
+     * @param descriptor the audio descriptor
+     */
+    @SystemApi
+    public AudioDescriptor(int standard, int encapsulationType, @NonNull byte[] descriptor) {
         mStandard = standard;
         mEncapsulationType = encapsulationType;
         mDescriptor = descriptor;
@@ -87,4 +100,66 @@
     public @AudioProfile.EncapsulationType int getEncapsulationType() {
         return mEncapsulationType;
     }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mStandard, mEncapsulationType, Arrays.hashCode(mDescriptor));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AudioDescriptor that = (AudioDescriptor) o;
+        return ((mStandard == that.mStandard)
+                && (mEncapsulationType == that.mEncapsulationType)
+                && (Arrays.equals(mDescriptor, that.mDescriptor)));
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("{");
+        sb.append("standard=" + mStandard);
+        sb.append(", encapsulation type=" + mEncapsulationType);
+        if (mDescriptor != null && mDescriptor.length > 0) {
+            sb.append(", descriptor=").append(Arrays.toString(mDescriptor));
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mStandard);
+        dest.writeInt(mEncapsulationType);
+        dest.writeByteArray(mDescriptor);
+    }
+
+    private AudioDescriptor(@NonNull Parcel in) {
+        mStandard = in.readInt();
+        mEncapsulationType = in.readInt();
+        mDescriptor = in.createByteArray();
+    }
+
+    public static final @NonNull Parcelable.Creator<AudioDescriptor> CREATOR =
+            new Parcelable.Creator<AudioDescriptor>() {
+                /**
+                 * Rebuilds an AudioDescriptor previously stored with writeToParcel().
+                 * @param p Parcel object to read the AudioDescriptor from
+                 * @return a new AudioDescriptor created from the data in the parcel
+                 */
+                public AudioDescriptor createFromParcel(Parcel p) {
+                    return new AudioDescriptor(p);
+                }
+
+                public AudioDescriptor[] newArray(int size) {
+                    return new AudioDescriptor[size];
+                }
+            };
 }
diff --git a/media/java/android/media/AudioDeviceAttributes.java b/media/java/android/media/AudioDeviceAttributes.java
index 1448c49..af3c295 100644
--- a/media/java/android/media/AudioDeviceAttributes.java
+++ b/media/java/android/media/AudioDeviceAttributes.java
@@ -18,12 +18,16 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -65,16 +69,27 @@
      * The unique address of the device. Some devices don't have addresses, only an empty string.
      */
     private final @NonNull String mAddress;
-
+    /**
+     * The non-unique name of the device. Some devices don't have names, only an empty string.
+     * Should not be used as a unique identifier for a device.
+     */
+    private final @NonNull String mName;
     /**
      * Is input or output device
      */
     private final @Role int mRole;
-
     /**
      * The internal audio device type
      */
     private final int mNativeType;
+    /**
+     * List of AudioProfiles supported by the device
+     */
+    private final @NonNull List<AudioProfile> mAudioProfiles;
+    /**
+     * List of AudioDescriptors supported by the device
+     */
+    private final @NonNull List<AudioDescriptor> mAudioDescriptors;
 
     /**
      * @hide
@@ -88,7 +103,10 @@
         mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
         mType = deviceInfo.getType();
         mAddress = deviceInfo.getAddress();
+        mName = String.valueOf(deviceInfo.getProductName());
         mNativeType = deviceInfo.getInternalType();
+        mAudioProfiles = deviceInfo.getAudioProfiles();
+        mAudioDescriptors = deviceInfo.getAudioDescriptors();
     }
 
     /**
@@ -100,7 +118,24 @@
      */
     @SystemApi
     public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
-                              @NonNull String address) {
+            @NonNull String address) {
+        this(role, type, address, "", new ArrayList<>(), new ArrayList<>());
+    }
+
+    /**
+     * @hide
+     * Constructor with specification of all attributes
+     * @param role indicates input or output role
+     * @param type the device type, as defined in {@link AudioDeviceInfo}
+     * @param address the address of the device, or an empty string for devices without one
+     * @param name the name of the device, or an empty string for devices without one
+     * @param profiles the list of AudioProfiles supported by the device
+     * @param descriptors the list of AudioDescriptors supported by the device
+     */
+    @SystemApi
+    public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
+            @NonNull String address, @NonNull String name, @NonNull List<AudioProfile> profiles,
+            @NonNull List<AudioDescriptor> descriptors) {
         Objects.requireNonNull(address);
         if (role != ROLE_OUTPUT && role != ROLE_INPUT) {
             throw new IllegalArgumentException("Invalid role " + role);
@@ -118,19 +153,37 @@
         mRole = role;
         mType = type;
         mAddress = address;
+        mName = name;
+        mAudioProfiles = profiles;
+        mAudioDescriptors = descriptors;
     }
 
     /**
      * @hide
-     * Constructor from internal device type and address
-     * @param type the internal device type, as defined in {@link AudioSystem}
+     * Constructor called from AudioSystem JNI when creating an AudioDeviceAttributes from a native
+     * AudioDeviceTypeAddr instance.
+     * @param nativeType the internal device type, as defined in {@link AudioSystem}
      * @param address the address of the device, or an empty string for devices without one
      */
     public AudioDeviceAttributes(int nativeType, @NonNull String address) {
+        this(nativeType, address, "");
+    }
+
+    /**
+     * @hide
+     * Constructor called from BtHelper to connect or disconnect a Bluetooth device.
+     * @param nativeType the internal device type, as defined in {@link AudioSystem}
+     * @param address the address of the device, or an empty string for devices without one
+     * @param name the name of the device, or an empty string for devices without one
+     */
+    public AudioDeviceAttributes(int nativeType, @NonNull String address, @NonNull String name) {
         mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
         mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
         mAddress = address;
+        mName = name;
         mNativeType = nativeType;
+        mAudioProfiles = new ArrayList<>();
+        mAudioDescriptors = new ArrayList<>();
     }
 
     /**
@@ -165,6 +218,16 @@
 
     /**
      * @hide
+     * Returns the name of the audio device, or an empty string for devices without one
+     * @return the device name
+     */
+    @SystemApi
+    public @NonNull String getName() {
+        return mName;
+    }
+
+    /**
+     * @hide
      * Returns the internal device type of a device
      * @return the internal device type
      */
@@ -172,9 +235,29 @@
         return mNativeType;
     }
 
+    /**
+     * @hide
+     * Returns the list of AudioProfiles supported by the device
+     * @return the list of AudioProfiles
+     */
+    @SystemApi
+    public @NonNull List<AudioProfile> getAudioProfiles() {
+        return mAudioProfiles;
+    }
+
+    /**
+     * @hide
+     * Returns the list of AudioDescriptors supported by the device
+     * @return the list of AudioDescriptors
+     */
+    @SystemApi
+    public @NonNull List<AudioDescriptor> getAudioDescriptors() {
+        return mAudioDescriptors;
+    }
+
     @Override
     public int hashCode() {
-        return Objects.hash(mRole, mType, mAddress);
+        return Objects.hash(mRole, mType, mAddress, mName, mAudioProfiles, mAudioDescriptors);
     }
 
     @Override
@@ -185,6 +268,25 @@
         AudioDeviceAttributes that = (AudioDeviceAttributes) o;
         return ((mRole == that.mRole)
                 && (mType == that.mType)
+                && mAddress.equals(that.mAddress)
+                && mName.equals(that.mName)
+                && mAudioProfiles.equals(that.mAudioProfiles)
+                && mAudioDescriptors.equals(that.mAudioDescriptors));
+    }
+
+    /**
+     * Returns true if the role, type and address are equal. Called to compare with an
+     * AudioDeviceAttributes that was created from a native AudioDeviceTypeAddr instance.
+     * @param o object to compare with
+     * @return whether role, type and address are equal
+     */
+    public boolean equalTypeAddress(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AudioDeviceAttributes that = (AudioDeviceAttributes) o;
+        return ((mRole == that.mRole)
+                && (mType == that.mType)
                 && mAddress.equals(that.mAddress));
     }
 
@@ -199,7 +301,10 @@
                 + " role:" + roleToString(mRole)
                 + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType)
                         : AudioSystem.getInputDeviceName(mNativeType))
-                + " addr:" + mAddress);
+                + " addr:" + mAddress
+                + " name:" + mName
+                + " profiles:" + mAudioProfiles.toString()
+                + " descriptors:" + mAudioDescriptors.toString());
     }
 
     @Override
@@ -212,14 +317,26 @@
         dest.writeInt(mRole);
         dest.writeInt(mType);
         dest.writeString(mAddress);
+        dest.writeString(mName);
         dest.writeInt(mNativeType);
+        dest.writeParcelableArray(
+                mAudioProfiles.toArray(new AudioProfile[mAudioProfiles.size()]), flags);
+        dest.writeParcelableArray(
+                mAudioDescriptors.toArray(new AudioDescriptor[mAudioDescriptors.size()]), flags);
     }
 
     private AudioDeviceAttributes(@NonNull Parcel in) {
         mRole = in.readInt();
         mType = in.readInt();
         mAddress = in.readString();
+        mName = in.readString();
         mNativeType = in.readInt();
+        AudioProfile[] audioProfilesArray =
+                in.readParcelableArray(AudioProfile.class.getClassLoader(), AudioProfile.class);
+        mAudioProfiles = new ArrayList<AudioProfile>(Arrays.asList(audioProfilesArray));
+        AudioDescriptor[] audioDescriptorsArray = in.readParcelableArray(
+                AudioDescriptor.class.getClassLoader(), AudioDescriptor.class);
+        mAudioDescriptors = new ArrayList<AudioDescriptor>(Arrays.asList(audioDescriptorsArray));
     }
 
     public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR =
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index dd17dc6..3d08959 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -421,7 +421,7 @@
      */
     public CharSequence getProductName() {
         String portName = mPort.name();
-        return portName.length() != 0 ? portName : android.os.Build.MODEL;
+        return (portName != null && portName.length() != 0) ? portName : android.os.Build.MODEL;
     }
 
     /**
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b8333fb..cdc3163 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5874,7 +5874,7 @@
         return false;
     }
 
-     /**
+    /**
      * Indicate wired accessory connection state change.
      * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
      * @param state  new connection state: 1 connected, 0 disconnected
@@ -5883,10 +5883,29 @@
      */
     @UnsupportedAppUsage
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
+    public void setWiredDeviceConnectionState(int device, int state, String address,
+            String name) {
+        final IAudioService service = getService();
+        int role = isOutputDevice(device)
+                ? AudioDeviceAttributes.ROLE_OUTPUT : AudioDeviceAttributes.ROLE_INPUT;
+        AudioDeviceAttributes attributes = new AudioDeviceAttributes(
+                role, AudioDeviceInfo.convertInternalDeviceToDeviceType(device), address,
+                name, new ArrayList<>()/*mAudioProfiles*/, new ArrayList<>()/*mAudioDescriptors*/);
+        setWiredDeviceConnectionState(attributes, state);
+    }
+
+    /**
+     * Indicate wired accessory connection state change and attributes.
+     * @param state      new connection state: 1 connected, 0 disconnected
+     * @param attributes attributes of the connected device
+     * {@hide}
+     */
+    @UnsupportedAppUsage
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
         final IAudioService service = getService();
         try {
-            service.setWiredDeviceConnectionState(type, state, address, name,
+            service.setWiredDeviceConnectionState(attributes, state,
                     mApplicationContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/media/java/android/media/AudioProfile.java b/media/java/android/media/AudioProfile.java
index ae8d0a5..5c5f837 100644
--- a/media/java/android/media/AudioProfile.java
+++ b/media/java/android/media/AudioProfile.java
@@ -18,10 +18,14 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 /**
@@ -33,7 +37,7 @@
  * be reported in different audio profiles. The application can choose any of the encapsulation
  * types.
  */
-public class AudioProfile {
+public class AudioProfile implements Parcelable {
     /**
      * No encapsulation type is specified.
      */
@@ -57,9 +61,19 @@
     private final int[] mChannelIndexMasks;
     private final int mEncapsulationType;
 
-    AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks,
-                 @NonNull int[] channelIndexMasks,
-                 int encapsulationType) {
+    /**
+     * @hide
+     * Constructor from format, sampling rates, channel masks, channel index masks and
+     * encapsulation type.
+     * @param format the audio format
+     * @param samplingRates the supported sampling rates
+     * @param channelMasks the supported channel masks
+     * @param channelIndexMasks the supported channel index masks
+     * @param encapsulationType the encapsulation type of the encoding format
+     */
+    @SystemApi
+    public AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks,
+                 @NonNull int[] channelIndexMasks, int encapsulationType) {
         mFormat = format;
         mSamplingRates = samplingRates;
         mChannelMasks = channelMasks;
@@ -114,6 +128,26 @@
     }
 
     @Override
+    public int hashCode() {
+        return Objects.hash(mFormat, Arrays.hashCode(mSamplingRates),
+                Arrays.hashCode(mChannelMasks), Arrays.hashCode(mChannelIndexMasks),
+                mEncapsulationType);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AudioProfile that = (AudioProfile) o;
+        return ((mFormat == that.mFormat)
+                && (hasIdenticalElements(mSamplingRates, that.mSamplingRates))
+                && (hasIdenticalElements(mChannelMasks, that.mChannelMasks))
+                && (hasIdenticalElements(mChannelIndexMasks, that.mChannelIndexMasks))
+                && (mEncapsulationType == that.mEncapsulationType));
+    }
+
+    @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("{");
         sb.append(AudioFormat.toLogFriendlyEncoding(mFormat));
@@ -126,6 +160,7 @@
         if (mChannelIndexMasks != null && mChannelIndexMasks.length > 0) {
             sb.append(", channel index masks=").append(Arrays.toString(mChannelIndexMasks));
         }
+        sb.append(", encapsulation type=" + mEncapsulationType);
         sb.append("}");
         return sb.toString();
     }
@@ -137,4 +172,50 @@
         return Arrays.stream(ints).mapToObj(anInt -> String.format("0x%02X", anInt))
                 .collect(Collectors.joining(", "));
     }
+
+    private static boolean hasIdenticalElements(int[] array1, int[] array2) {
+        int[] sortedArray1 = Arrays.copyOf(array1, array1.length);
+        Arrays.sort(sortedArray1);
+        int[] sortedArray2 = Arrays.copyOf(array2, array2.length);
+        Arrays.sort(sortedArray2);
+        return Arrays.equals(sortedArray1, sortedArray2);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mFormat);
+        dest.writeIntArray(mSamplingRates);
+        dest.writeIntArray(mChannelMasks);
+        dest.writeIntArray(mChannelIndexMasks);
+        dest.writeInt(mEncapsulationType);
+    }
+
+    private AudioProfile(@NonNull Parcel in) {
+        mFormat = in.readInt();
+        mSamplingRates = in.createIntArray();
+        mChannelMasks = in.createIntArray();
+        mChannelIndexMasks = in.createIntArray();
+        mEncapsulationType = in.readInt();
+    }
+
+    public static final @NonNull Parcelable.Creator<AudioProfile> CREATOR =
+            new Parcelable.Creator<AudioProfile>() {
+                /**
+                 * Rebuilds an AudioProfile previously stored with writeToParcel().
+                 * @param p Parcel object to read the AudioProfile from
+                 * @return a new AudioProfile created from the data in the parcel
+                 */
+                public AudioProfile createFromParcel(Parcel p) {
+                    return new AudioProfile(p);
+                }
+
+                public AudioProfile[] newArray(int size) {
+                    return new AudioProfile[size];
+                }
+            };
 }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 1b46a50..536b4ad 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -26,10 +26,12 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.media.audio.common.AidlConversion;
 import android.media.audiofx.AudioEffect;
 import android.media.audiopolicy.AudioMix;
 import android.os.Build;
 import android.os.IBinder;
+import android.os.Parcel;
 import android.os.Vibrator;
 import android.telephony.TelephonyManager;
 import android.util.Log;
@@ -1555,9 +1557,24 @@
      *     {@link #AUDIO_STATUS_ERROR} or {@link #AUDIO_STATUS_SERVER_DIED}
      */
     @UnsupportedAppUsage
-    public static native int setDeviceConnectionState(int device, int state,
-                                                      String device_address, String device_name,
-                                                      int codecFormat);
+    public static int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+            int codecFormat) {
+        android.media.audio.common.AudioPort port =
+                AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes);
+        Parcel parcel = Parcel.obtain();
+        port.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        try {
+            return setDeviceConnectionState(state, parcel, codecFormat);
+        } finally {
+            parcel.recycle();
+        }
+    }
+    /**
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public static native int setDeviceConnectionState(int state, Parcel parcel, int codecFormat);
     /** @hide */
     @UnsupportedAppUsage
     public static native int getDeviceConnectionState(int device, String device_address);
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4451c64..fec14de 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -215,8 +215,7 @@
     IRingtonePlayer getRingtonePlayer();
     int getUiSoundsStreamType();
 
-    void setWiredDeviceConnectionState(int type, int state, String address, String name,
-            String caller);
+    void setWiredDeviceConnectionState(in AudioDeviceAttributes aa, int state, String caller);
 
     @UnsupportedAppUsage
     AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java
index 0045018..e609226 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -67,7 +67,7 @@
     @NonNull
     private final List<String> mRequiredFeatures;
     @NonNull
-    private final List<String> mPackagesOrder;
+    private final List<String> mPackageOrder;
     @NonNull
     private final List<String> mAllowedPackages;
 
@@ -86,7 +86,7 @@
     RouteDiscoveryPreference(@NonNull Builder builder) {
         mPreferredFeatures = builder.mPreferredFeatures;
         mRequiredFeatures = builder.mRequiredFeatures;
-        mPackagesOrder = builder.mPackageOrder;
+        mPackageOrder = builder.mPackageOrder;
         mAllowedPackages = builder.mAllowedPackages;
         mShouldPerformActiveScan = builder.mActiveScan;
         mExtras = builder.mExtras;
@@ -95,7 +95,7 @@
     RouteDiscoveryPreference(@NonNull Parcel in) {
         mPreferredFeatures = in.createStringArrayList();
         mRequiredFeatures = in.createStringArrayList();
-        mPackagesOrder = in.createStringArrayList();
+        mPackageOrder = in.createStringArrayList();
         mAllowedPackages = in.createStringArrayList();
         mShouldPerformActiveScan = in.readBoolean();
         mExtras = in.readBundle();
@@ -144,7 +144,7 @@
      */
     @NonNull
     public List<String> getDeduplicationPackageOrder() {
-        return mPackagesOrder;
+        return mPackageOrder;
     }
 
     /**
@@ -175,7 +175,7 @@
      * @see #getDeduplicationPackageOrder()
      */
     public boolean shouldRemoveDuplicates() {
-        return !mPackagesOrder.isEmpty();
+        return !mPackageOrder.isEmpty();
     }
 
     /**
@@ -194,7 +194,7 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeStringList(mPreferredFeatures);
         dest.writeStringList(mRequiredFeatures);
-        dest.writeStringList(mPackagesOrder);
+        dest.writeStringList(mPackageOrder);
         dest.writeStringList(mAllowedPackages);
         dest.writeBoolean(mShouldPerformActiveScan);
         dest.writeBundle(mExtras);
@@ -225,14 +225,14 @@
         RouteDiscoveryPreference other = (RouteDiscoveryPreference) o;
         return Objects.equals(mPreferredFeatures, other.mPreferredFeatures)
                 && Objects.equals(mRequiredFeatures, other.mRequiredFeatures)
-                && Objects.equals(mPackagesOrder, other.mPackagesOrder)
+                && Objects.equals(mPackageOrder, other.mPackageOrder)
                 && Objects.equals(mAllowedPackages, other.mAllowedPackages)
                 && mShouldPerformActiveScan == other.mShouldPerformActiveScan;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mPreferredFeatures, mRequiredFeatures, mPackagesOrder, mAllowedPackages,
+        return Objects.hash(mPreferredFeatures, mRequiredFeatures, mPackageOrder, mAllowedPackages,
                 mShouldPerformActiveScan);
     }
 
@@ -271,21 +271,31 @@
         }
 
         /**
-         * A constructor to combine all the preferences into a single preference.
-         * It ignores extras of preferences.
+         * A constructor to combine multiple preferences into a single preference. The combined
+         * preference will discover a superset of the union of the routes discoverable by each of
+         * the individual preferences.
+         * <p>
+         * When routes need to be discovered for multiple preferences, the combined preference can
+         * be used to query route providers once and obtain all routes of interest. The obtained
+         * routes can then be filtered for each of the individual preferences. This is typically
+         * more efficient than querying route providers with each of the individual preferences.
          *
          * @hide
          */
         public Builder(@NonNull Collection<RouteDiscoveryPreference> preferences) {
             Objects.requireNonNull(preferences, "preferences must not be null");
 
-            Set<String> routeFeatureSet = new HashSet<>();
-            mActiveScan = false;
+            Set<String> preferredFeatures = new HashSet<>();
+            boolean activeScan = false;
             for (RouteDiscoveryPreference preference : preferences) {
-                routeFeatureSet.addAll(preference.mPreferredFeatures);
-                mActiveScan |= preference.mShouldPerformActiveScan;
+                preferredFeatures.addAll(preference.mPreferredFeatures);
+                activeScan |= preference.mShouldPerformActiveScan;
             }
-            mPreferredFeatures = new ArrayList<>(routeFeatureSet);
+            mPreferredFeatures = new ArrayList<>(preferredFeatures);
+            mRequiredFeatures = List.of();
+            mPackageOrder = List.of();
+            mAllowedPackages = List.of();
+            mActiveScan = activeScan;
         }
 
         /**
diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java
index 1053fb7..f17189d 100644
--- a/media/java/android/media/audio/common/AidlConversion.java
+++ b/media/java/android/media/audio/common/AidlConversion.java
@@ -17,12 +17,17 @@
 package android.media.audio.common;
 
 import android.annotation.NonNull;
+import android.media.AudioDescriptor;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioFormat;
+import android.media.AudioSystem;
 import android.media.MediaFormat;
 import android.os.Parcel;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.stream.Collectors;
+
 /**
  * This class provides utility functions for converting between
  * the AIDL types defined in 'android.media.audio.common' and:
@@ -525,6 +530,351 @@
         }
     }
 
+    /**
+     * Convert from SDK AudioDeviceAttributes to AIDL AudioPort.
+     */
+    public static AudioPort api2aidl_AudioDeviceAttributes_AudioPort(
+            @NonNull AudioDeviceAttributes attributes) {
+        AudioPort port = new AudioPort();
+        port.name = attributes.getName();
+        // TO DO: b/211611504 Convert attributes.getAudioProfiles() to AIDL as well.
+        port.profiles = new AudioProfile[]{};
+        port.extraAudioDescriptors = attributes.getAudioDescriptors().stream()
+                .map(descriptor -> api2aidl_AudioDescriptor_ExtraAudioDescriptor(descriptor))
+                .collect(Collectors.toList()).toArray(ExtraAudioDescriptor[]::new);
+        port.flags = new AudioIoFlags();
+        port.gains = new AudioGain[]{};
+        AudioPortDeviceExt deviceExt = new AudioPortDeviceExt();
+        deviceExt.device = new AudioDevice();
+        deviceExt.encodedFormats = new AudioFormatDescription[]{};
+        deviceExt.device.type =
+                api2aidl_NativeType_AudioDeviceDescription(attributes.getInternalType());
+        deviceExt.device.address = AudioDeviceAddress.id(attributes.getAddress());
+        port.ext = AudioPortExt.device(deviceExt);
+        return port;
+    }
+
+    /**
+     * Convert from SDK AudioDescriptor to AIDL ExtraAudioDescriptor.
+     */
+    public static ExtraAudioDescriptor api2aidl_AudioDescriptor_ExtraAudioDescriptor(
+            @NonNull AudioDescriptor descriptor) {
+        ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
+        extraDescriptor.standard =
+                api2aidl_AudioDescriptorStandard_AudioStandard(descriptor.getStandard());
+        extraDescriptor.audioDescriptor = descriptor.getDescriptor();
+        extraDescriptor.encapsulationType =
+                api2aidl_AudioProfileEncapsulationType_AudioEncapsulationType(
+                        descriptor.getEncapsulationType());
+        return extraDescriptor;
+    }
+
+    /**
+     * Convert from SDK AudioDescriptor to AIDL ExtraAudioDescriptor.
+     */
+    public static @NonNull AudioDescriptor aidl2api_ExtraAudioDescriptor_AudioDescriptor(
+            @NonNull ExtraAudioDescriptor extraDescriptor) {
+        AudioDescriptor descriptor = new AudioDescriptor(
+                aidl2api_AudioStandard_AudioDescriptorStandard(extraDescriptor.standard),
+                aidl2api_AudioEncapsulationType_AudioProfileEncapsulationType(
+                        extraDescriptor.encapsulationType),
+                extraDescriptor.audioDescriptor);
+        return descriptor;
+    }
+
+    /**
+     * Convert from SDK AudioDescriptor#mStandard to AIDL AudioStandard
+     */
+    @AudioStandard
+    public static int api2aidl_AudioDescriptorStandard_AudioStandard(
+            @AudioDescriptor.AudioDescriptorStandard int standard) {
+        switch (standard) {
+            case AudioDescriptor.STANDARD_EDID:
+                return AudioStandard.EDID;
+            case AudioDescriptor.STANDARD_NONE:
+            default:
+                return AudioStandard.NONE;
+        }
+    }
+
+    /**
+     * Convert from AIDL AudioStandard to SDK AudioDescriptor#mStandard
+     */
+    @AudioDescriptor.AudioDescriptorStandard
+    public static int aidl2api_AudioStandard_AudioDescriptorStandard(@AudioStandard int standard) {
+        switch (standard) {
+            case AudioStandard.EDID:
+                return AudioDescriptor.STANDARD_EDID;
+            case AudioStandard.NONE:
+            default:
+                return AudioDescriptor.STANDARD_NONE;
+        }
+    }
+
+    /**
+     * Convert from SDK AudioProfile.EncapsulationType to AIDL AudioEncapsulationType
+     */
+    @AudioEncapsulationType
+    public static int api2aidl_AudioProfileEncapsulationType_AudioEncapsulationType(
+            @android.media.AudioProfile.EncapsulationType int type) {
+        switch (type) {
+            case android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937:
+                return AudioEncapsulationType.IEC61937;
+            case android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE:
+            default:
+                return AudioEncapsulationType.NONE;
+        }
+    }
+
+    /**
+     * Convert from AIDL AudioEncapsulationType to SDK AudioProfile.EncapsulationType
+     */
+    @android.media.AudioProfile.EncapsulationType
+    public static int aidl2api_AudioEncapsulationType_AudioProfileEncapsulationType(
+            @AudioEncapsulationType int type) {
+        switch (type) {
+            case AudioEncapsulationType.IEC61937:
+                return android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937;
+            case AudioEncapsulationType.NONE:
+            default:
+                return android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE;
+        }
+    }
+
+    /**
+     * Convert from SDK native type to AIDL AudioDeviceDescription
+     */
+    public static AudioDeviceDescription api2aidl_NativeType_AudioDeviceDescription(
+            int nativeType) {
+        AudioDeviceDescription aidl = new AudioDeviceDescription();
+        aidl.connection = "";
+        switch (nativeType) {
+            case AudioSystem.DEVICE_OUT_EARPIECE:
+                aidl.type = AudioDeviceType.OUT_SPEAKER_EARPIECE;
+                break;
+            case AudioSystem.DEVICE_OUT_SPEAKER:
+                aidl.type = AudioDeviceType.OUT_SPEAKER;
+                break;
+            case AudioSystem.DEVICE_OUT_WIRED_HEADPHONE:
+                aidl.type = AudioDeviceType.OUT_HEADPHONE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+                aidl.type = AudioDeviceType.OUT_CARKIT;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+                aidl.type = AudioDeviceType.OUT_HEADPHONE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+                aidl.type = AudioDeviceType.OUT_SPEAKER;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+                break;
+            case AudioSystem.DEVICE_OUT_TELEPHONY_TX:
+                aidl.type = AudioDeviceType.OUT_TELEPHONY_TX;
+                break;
+            case AudioSystem.DEVICE_OUT_AUX_LINE:
+                aidl.type = AudioDeviceType.OUT_LINE_AUX;
+                break;
+            case AudioSystem.DEVICE_OUT_SPEAKER_SAFE:
+                aidl.type = AudioDeviceType.OUT_SPEAKER_SAFE;
+                break;
+            case AudioSystem.DEVICE_OUT_HEARING_AID:
+                aidl.type = AudioDeviceType.OUT_HEARING_AID;
+                aidl.connection = AudioDeviceDescription.CONNECTION_WIRELESS;
+                break;
+            case AudioSystem.DEVICE_OUT_ECHO_CANCELLER:
+                aidl.type = AudioDeviceType.OUT_ECHO_CANCELLER;
+                break;
+            case AudioSystem.DEVICE_OUT_BLE_SPEAKER:
+                aidl.type = AudioDeviceType.OUT_SPEAKER;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+                break;
+            case AudioSystem.DEVICE_IN_BUILTIN_MIC:
+                aidl.type = AudioDeviceType.IN_MICROPHONE;
+                break;
+            case AudioSystem.DEVICE_IN_BACK_MIC:
+                aidl.type = AudioDeviceType.IN_MICROPHONE_BACK;
+                break;
+            case AudioSystem.DEVICE_IN_TELEPHONY_RX:
+                aidl.type = AudioDeviceType.IN_TELEPHONY_RX;
+                break;
+            case AudioSystem.DEVICE_IN_TV_TUNER:
+                aidl.type = AudioDeviceType.IN_TV_TUNER;
+                break;
+            case AudioSystem.DEVICE_IN_LOOPBACK:
+                aidl.type = AudioDeviceType.IN_LOOPBACK;
+                break;
+            case AudioSystem.DEVICE_IN_BLUETOOTH_BLE:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+                break;
+            case AudioSystem.DEVICE_IN_ECHO_REFERENCE:
+                aidl.type = AudioDeviceType.IN_ECHO_REFERENCE;
+                break;
+            case AudioSystem.DEVICE_IN_WIRED_HEADSET:
+                aidl.type = AudioDeviceType.IN_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_OUT_WIRED_HEADSET:
+                aidl.type = AudioDeviceType.OUT_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET:
+                aidl.type = AudioDeviceType.IN_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+                aidl.type = AudioDeviceType.OUT_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+                break;
+            case AudioSystem.DEVICE_IN_HDMI:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI;
+                break;
+            case AudioSystem.DEVICE_OUT_HDMI:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI;
+                break;
+            case AudioSystem.DEVICE_IN_REMOTE_SUBMIX:
+                aidl.type = AudioDeviceType.IN_SUBMIX;
+                break;
+            case AudioSystem.DEVICE_OUT_REMOTE_SUBMIX:
+                aidl.type = AudioDeviceType.OUT_SUBMIX;
+                break;
+            case AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET:
+                aidl.type = AudioDeviceType.IN_DOCK;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET:
+                aidl.type = AudioDeviceType.OUT_DOCK;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET:
+                aidl.type = AudioDeviceType.IN_DOCK;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET:
+                aidl.type = AudioDeviceType.OUT_DOCK;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_IN_USB_ACCESSORY:
+                aidl.type = AudioDeviceType.IN_ACCESSORY;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_OUT_USB_ACCESSORY:
+                aidl.type = AudioDeviceType.OUT_ACCESSORY;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_IN_USB_DEVICE:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_OUT_USB_DEVICE:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_IN_FM_TUNER:
+                aidl.type = AudioDeviceType.IN_FM_TUNER;
+                break;
+            case AudioSystem.DEVICE_OUT_FM:
+                aidl.type = AudioDeviceType.OUT_FM;
+                break;
+            case AudioSystem.DEVICE_IN_LINE:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_OUT_LINE:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+                break;
+            case AudioSystem.DEVICE_IN_SPDIF:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_SPDIF;
+                break;
+            case AudioSystem.DEVICE_OUT_SPDIF:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_SPDIF;
+                break;
+            case AudioSystem.DEVICE_IN_BLUETOOTH_A2DP:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+                break;
+            case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+                break;
+            case AudioSystem.DEVICE_IN_IP:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_IP_V4;
+                break;
+            case AudioSystem.DEVICE_OUT_IP:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_IP_V4;
+                break;
+            case AudioSystem.DEVICE_IN_BUS:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BUS;
+                break;
+            case AudioSystem.DEVICE_OUT_BUS:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BUS;
+                break;
+            case AudioSystem.DEVICE_IN_PROXY:
+                aidl.type = AudioDeviceType.IN_AFE_PROXY;
+                break;
+            case AudioSystem.DEVICE_OUT_PROXY:
+                aidl.type = AudioDeviceType.OUT_AFE_PROXY;
+                break;
+            case AudioSystem.DEVICE_IN_USB_HEADSET:
+                aidl.type = AudioDeviceType.IN_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_OUT_USB_HEADSET:
+                aidl.type = AudioDeviceType.OUT_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+                break;
+            case AudioSystem.DEVICE_IN_HDMI_ARC:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_ARC;
+                break;
+            case AudioSystem.DEVICE_OUT_HDMI_ARC:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_ARC;
+                break;
+            case AudioSystem.DEVICE_IN_HDMI_EARC:
+                aidl.type = AudioDeviceType.IN_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_EARC;
+                break;
+            case AudioSystem.DEVICE_OUT_HDMI_EARC:
+                aidl.type = AudioDeviceType.OUT_DEVICE;
+                aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_EARC;
+                break;
+            case AudioSystem.DEVICE_IN_BLE_HEADSET:
+                aidl.type = AudioDeviceType.IN_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+                break;
+            case AudioSystem.DEVICE_OUT_BLE_HEADSET:
+                aidl.type = AudioDeviceType.OUT_HEADSET;
+                aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+                break;
+            case AudioSystem.DEVICE_IN_DEFAULT:
+                aidl.type = AudioDeviceType.IN_DEFAULT;
+                break;
+            case AudioSystem.DEVICE_OUT_DEFAULT:
+                aidl.type = AudioDeviceType.OUT_DEFAULT;
+                break;
+            default:
+                aidl.type = AudioDeviceType.NONE;
+        }
+        return aidl;
+    }
+
     private static native int aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(
             Parcel aidl, boolean isInput);
     private static native Parcel legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(
diff --git a/media/java/android/media/tv/BroadcastInfoRequest.java b/media/java/android/media/tv/BroadcastInfoRequest.java
index f7a52f2..cbd8c1f 100644
--- a/media/java/android/media/tv/BroadcastInfoRequest.java
+++ b/media/java/android/media/tv/BroadcastInfoRequest.java
@@ -56,6 +56,8 @@
                     switch (type) {
                         case TvInputManager.BROADCAST_INFO_TYPE_TS:
                             return TsRequest.createFromParcelBody(source);
+                        case TvInputManager.BROADCAST_INFO_TYPE_TABLE:
+                            return TableRequest.createFromParcelBody(source);
                         case TvInputManager.BROADCAST_INFO_TYPE_SECTION:
                             return SectionRequest.createFromParcelBody(source);
                         case TvInputManager.BROADCAST_INFO_TYPE_PES:
diff --git a/media/java/android/media/tv/BroadcastInfoResponse.java b/media/java/android/media/tv/BroadcastInfoResponse.java
index ff4ec15..4ba2b2c 100644
--- a/media/java/android/media/tv/BroadcastInfoResponse.java
+++ b/media/java/android/media/tv/BroadcastInfoResponse.java
@@ -57,6 +57,8 @@
                     switch (type) {
                         case TvInputManager.BROADCAST_INFO_TYPE_TS:
                             return TsResponse.createFromParcelBody(source);
+                        case TvInputManager.BROADCAST_INFO_TYPE_TABLE:
+                            return TableResponse.createFromParcelBody(source);
                         case TvInputManager.BROADCAST_INFO_TYPE_SECTION:
                             return SectionResponse.createFromParcelBody(source);
                         case TvInputManager.BROADCAST_INFO_TYPE_PES:
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 14accaa..a3e731b 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -623,21 +623,21 @@
      * <p>This functionality is only available in Tuner version 2.0 and higher and will otherwise
      * be a no-op. Use {@link TunerVersionChecker#getTunerVersion()} to get the version information.
      *
-     * @param delayInMs specifies the duration of the delay in milliseconds.
+     * @param durationInMs specifies the duration of the delay in milliseconds.
      * @return one of the following results: {@link Tuner#RESULT_SUCCESS},
      * {@link Tuner#RESULT_UNAVAILABLE}, {@link Tuner#RESULT_NOT_INITIALIZED},
      * {@link Tuner#RESULT_INVALID_STATE}, {@link Tuner#RESULT_INVALID_ARGUMENT},
      * {@link Tuner#RESULT_OUT_OF_MEMORY}, or {@link Tuner#RESULT_UNKNOWN_ERROR}.
      */
-    public int delayCallbackUntilMillisElapsed(long delayInMs) {
+    public int delayCallbackForDurationMillis(long durationInMs) {
         if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
                   TunerVersionChecker.TUNER_VERSION_2_0, "setTimeDelayHint")) {
             return Tuner.RESULT_UNAVAILABLE;
         }
 
-        if (delayInMs >= 0 && delayInMs <= Integer.MAX_VALUE) {
+        if (durationInMs >= 0 && durationInMs <= Integer.MAX_VALUE) {
             synchronized (mLock) {
-                return nativeSetTimeDelayHint((int) delayInMs);
+                return nativeSetTimeDelayHint((int) durationInMs);
             }
         }
         return Tuner.RESULT_INVALID_ARGUMENT;
@@ -653,20 +653,20 @@
      * <p>This functionality is only available in Tuner version 2.0 and higher and will otherwise
      * be a no-op. Use {@link TunerVersionChecker#getTunerVersion()} to get the version information.
      *
-     * @param delayInBytes specifies the duration of the delay in bytes.
+     * @param bytesAccumulated specifies the delay condition in bytes.
      * @return one of the following results: {@link Tuner#RESULT_SUCCESS},
      * {@link Tuner#RESULT_UNAVAILABLE}, {@link Tuner#RESULT_NOT_INITIALIZED},
      * {@link Tuner#RESULT_INVALID_STATE}, {@link Tuner#RESULT_INVALID_ARGUMENT},
      * {@link Tuner#RESULT_OUT_OF_MEMORY}, or {@link Tuner#RESULT_UNKNOWN_ERROR}.
      */
-    public int delayCallbackUntilBytesAccumulated(int delayInBytes) {
+    public int delayCallbackUntilBytesAccumulated(int bytesAccumulated) {
         if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
                   TunerVersionChecker.TUNER_VERSION_2_0, "setTimeDelayHint")) {
             return Tuner.RESULT_UNAVAILABLE;
         }
 
         synchronized (mLock) {
-            return nativeSetDataSizeDelayHint(delayInBytes);
+            return nativeSetDataSizeDelayHint(bytesAccumulated);
         }
     }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index c1e9b38..9fbea72 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -25,6 +25,9 @@
 import android.media.tv.tuner.TunerVersionChecker;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * A Frontend Status class that contains the metrics of the active frontend.
@@ -1086,22 +1089,26 @@
     }
 
     /**
-     * Gets an array of all PLPs information of ATSC3 frontend, which includes both tuned and not
+     * Gets a list of all PLPs information of ATSC3 frontend, which includes both tuned and not
      * tuned PLPs for currently watching service.
      *
-     * <p>This query is only supported by Tuner HAL 2.0 or higher. Unsupported version or if HAL
-     * doesn't return all PLPs information will throw IllegalStateException. Use
-     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     * <p>This query is only supported by Tuner HAL 2.0 or higher. Unsupported version will throw
+     * UnsupportedOperationException. Use {@link TunerVersionChecker#getTunerVersion()} to check
+     * the version.
+     *
+     * @return a list of all PLPs information. It is empty if HAL doesn't return all PLPs
+     *         information status.
      */
-    @SuppressLint("ArrayReturn")
     @NonNull
-    public Atsc3PlpInfo[] getAllAtsc3PlpInfo() {
-        TunerVersionChecker.checkHigherOrEqualVersionTo(
-                TunerVersionChecker.TUNER_VERSION_2_0, "Atsc3PlpInfo all status");
-        if (mAllPlpInfo == null) {
-            throw new IllegalStateException("Atsc3PlpInfo all status is empty");
+    public List<Atsc3PlpInfo> getAllAtsc3PlpInfo() {
+        if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                    TunerVersionChecker.TUNER_VERSION_2_0, "Atsc3PlpInfo all status")) {
+            throw new UnsupportedOperationException("Atsc3PlpInfo all status is empty");
         }
-        return mAllPlpInfo;
+        if (mAllPlpInfo == null) {
+            return Collections.EMPTY_LIST;
+        }
+        return Arrays.asList(mAllPlpInfo);
     }
 
     /**
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index d8f48c2..20d711c 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -103,6 +103,7 @@
     private int mDeviceType;
     private String mHostType;
     private boolean mSkipThumbForHost = false;
+    private volatile boolean mHostIsWindows = false;
 
     private MtpServer mServer;
     private MtpStorageManager mManager;
@@ -358,7 +359,7 @@
     }
 
     public void addStorage(StorageVolume storage) {
-        MtpStorage mtpStorage = mManager.addMtpStorage(storage);
+        MtpStorage mtpStorage = mManager.addMtpStorage(storage, () -> mHostIsWindows);
         mStorageMap.put(storage.getPath(), mtpStorage);
         if (mServer != null) {
             mServer.addStorage(mtpStorage);
@@ -413,6 +414,7 @@
         }
         mHostType = "";
         mSkipThumbForHost = false;
+        mHostIsWindows = false;
     }
 
     @VisibleForNative
@@ -736,10 +738,12 @@
                         : MtpConstants.RESPONSE_GENERAL_ERROR);
             case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
                 mHostType = stringValue;
+                Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
+                        + "=" + stringValue);
                 if (stringValue.startsWith("Android/")) {
-                    Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
-                            + "=" + stringValue);
                     mSkipThumbForHost = true;
+                } else if (stringValue.startsWith("Windows/")) {
+                    mHostIsWindows = true;
                 }
                 return MtpConstants.RESPONSE_OK;
         }
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 88c32a3..a3754e90 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -19,6 +19,8 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.storage.StorageVolume;
 
+import java.util.function.Supplier;
+
 /**
  * This class represents a storage unit on an MTP device.
  * Used only for MTP support in USB responder mode.
@@ -33,14 +35,16 @@
     private final boolean mRemovable;
     private final long mMaxFileSize;
     private final String mVolumeName;
+    private final Supplier<Boolean> mIsHostWindows;
 
-    public MtpStorage(StorageVolume volume, int storageId) {
+    public MtpStorage(StorageVolume volume, int storageId, Supplier<Boolean> isHostWindows) {
         mStorageId = storageId;
         mPath = volume.getPath();
         mDescription = volume.getDescription(null);
         mRemovable = volume.isRemovable();
         mMaxFileSize = volume.getMaxFileSize();
         mVolumeName = volume.getMediaStoreVolumeName();
+        mIsHostWindows = isHostWindows;
     }
 
     /**
@@ -93,4 +97,13 @@
     public String getVolumeName() {
         return mVolumeName;
     }
+
+    /**
+     * Returns true if the mtp host of this storage is Windows.
+     *
+     * @return is host Windows
+     */
+    public boolean isHostWindows() {
+        return mIsHostWindows.get();
+    }
 }
diff --git a/media/java/android/mtp/MtpStorageManager.java b/media/java/android/mtp/MtpStorageManager.java
index 0bede0d..e9426cf 100644
--- a/media/java/android/mtp/MtpStorageManager.java
+++ b/media/java/android/mtp/MtpStorageManager.java
@@ -18,7 +18,11 @@
 
 import android.media.MediaFile;
 import android.os.FileObserver;
+import android.os.SystemProperties;
 import android.os.storage.StorageVolume;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
 import android.util.Log;
 
 import com.android.internal.util.Preconditions;
@@ -35,6 +39,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Supplier;
 
 /**
  * MtpStorageManager provides functionality for listing, tracking, and notifying MtpServer of
@@ -199,7 +204,38 @@
         }
 
         public long getSize() {
-            return mIsDir ? 0 : getPath().toFile().length();
+            return mIsDir ? 0 : maybeApplyTranscodeLengthWorkaround(getPath().toFile().length());
+        }
+
+        private long maybeApplyTranscodeLengthWorkaround(long length) {
+            // Windows truncates transferred files to the size advertised in the object property.
+            if (mStorage.isHostWindows() && isTranscodeMtpEnabled() && isFileTranscodeSupported()) {
+                // If the file supports transcoding, we double the returned size to accommodate
+                // the increase in size from transcoding to AVC. This is the same heuristic
+                // applied in the FUSE daemon (MediaProvider).
+                return length * 2;
+            }
+            return length;
+        }
+
+        private boolean isTranscodeMtpEnabled() {
+            return SystemProperties.getBoolean("sys.fuse.transcode_mtp", false);
+        }
+
+        private boolean isFileTranscodeSupported() {
+            // Check if the file supports transcoding by reading the |st_nlinks| struct stat
+            // field. This will be > 1 if the file supports transcoding. The FUSE daemon
+            // sets the field accordingly to enable the MTP stack workaround some Windows OS
+            // MTP client bug where they ignore the size returned as part of getting the MTP
+            // object, see MtpServer#doGetObject.
+            final Path path = getPath();
+            try {
+                StructStat stat = Os.stat(path.toString());
+                return stat.st_nlink > 1;
+            } catch (ErrnoException e) {
+                Log.w(TAG, "Failed to stat path: " + getPath() + ". Ignoring transcoding.");
+                return false;
+            }
         }
 
         public Path getPath() {
@@ -420,10 +456,12 @@
      * @param volume Storage to add.
      * @return the associated MtpStorage
      */
-    public synchronized MtpStorage addMtpStorage(StorageVolume volume) {
+    public synchronized MtpStorage addMtpStorage(StorageVolume volume,
+                                                 Supplier<Boolean> isHostWindows) {
         int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1;
-        MtpStorage storage = new MtpStorage(volume, storageId);
-        MtpObject root = new MtpObject(storage.getPath(), storageId, storage, null, true);
+        MtpStorage storage = new MtpStorage(volume, storageId, isHostWindows);
+        MtpObject root = new MtpObject(storage.getPath(), storageId, storage, /* parent= */ null,
+                                       /* isDir= */ true);
         mRoots.put(storageId, root);
         return storage;
     }
diff --git a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
index abdc7e5..a6a5568 100644
--- a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
+++ b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
@@ -160,10 +160,11 @@
                 Log.d(TAG, "sendObjectInfoChanged: " + id);
                 objectsInfoChanged.add(id);
             }
-        }, null);
+        }, /* subdirectories= */ null);
 
-        mainMtpStorage = manager.addMtpStorage(mainStorage);
-        secondaryMtpStorage = manager.addMtpStorage(secondaryStorage);
+        mainMtpStorage = manager.addMtpStorage(mainStorage, /* isHostWindows= */ () -> false);
+        secondaryMtpStorage = manager.addMtpStorage(secondaryStorage,
+                                                    /* isHostWindows= */ () -> false);
     }
 
     @After
diff --git a/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
index 414de89..0957390 100644
--- a/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
+++ b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
@@ -16,8 +16,18 @@
 
 package android.media.audio.common;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
 import android.media.AudioAttributes;
+import android.media.AudioDescriptor;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
+import android.media.AudioProfile;
 import android.media.AudioSystem;
 import android.media.AudioTrack;
 import android.media.MediaFormat;
@@ -25,11 +35,12 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
-import static org.junit.Assert.*;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+
 /**
  * Unit tests for AidlConversion utilities.
  *
@@ -417,10 +428,102 @@
                 () -> AidlConversion.legacy2aidl_audio_usage_t_AudioUsage(sInvalidValue));
     }
 
+    @Test
+    public void testAudioDescriptorConversion_Default() {
+        ExtraAudioDescriptor aidl = createDefaultDescriptor();
+        AudioDescriptor audioDescriptor =
+                AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(aidl);
+        assertEquals(AudioDescriptor.STANDARD_NONE, audioDescriptor.getStandard());
+        assertEquals(
+                AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, audioDescriptor.getEncapsulationType());
+        assertTrue(Arrays.equals(new byte[]{}, audioDescriptor.getDescriptor()));
+
+        ExtraAudioDescriptor reconstructedExtraDescriptor =
+                AidlConversion.api2aidl_AudioDescriptor_ExtraAudioDescriptor(audioDescriptor);
+        assertEquals(aidl, reconstructedExtraDescriptor);
+    }
+
+    @Test
+    public void testAudioDescriptorConversion() {
+        ExtraAudioDescriptor aidl = createEncapsulationDescriptor(new byte[]{0x05, 0x18, 0x4A});
+        AudioDescriptor audioDescriptor =
+                AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(aidl);
+        assertEquals(AudioDescriptor.STANDARD_EDID, audioDescriptor.getStandard());
+        assertEquals(AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937,
+                audioDescriptor.getEncapsulationType());
+        assertTrue(Arrays.equals(new byte[]{0x05, 0x18, 0x4A}, audioDescriptor.getDescriptor()));
+
+        ExtraAudioDescriptor reconstructedExtraDescriptor =
+                AidlConversion.api2aidl_AudioDescriptor_ExtraAudioDescriptor(audioDescriptor);
+        assertEquals(aidl, reconstructedExtraDescriptor);
+    }
+
+    @Test
+    public void testAudioDeviceAttributesConversion_Default() {
+        AudioDeviceAttributes attributes =
+                new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_DEFAULT, "myAddress");
+        AudioPort port = AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes);
+        assertEquals("", port.name);
+        assertEquals(0, port.extraAudioDescriptors.length);
+        assertEquals("myAddress", port.ext.getDevice().device.address.getId());
+        assertEquals("", port.ext.getDevice().device.type.connection);
+        assertEquals(AudioDeviceType.OUT_DEFAULT, port.ext.getDevice().device.type.type);
+    }
+
+    @Test
+    public void testAudioDeviceAttributesConversion() {
+        AudioDescriptor audioDescriptor1 =
+                AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(
+                        createEncapsulationDescriptor(new byte[]{0x05, 0x18, 0x4A}));
+
+        AudioDescriptor audioDescriptor2 =
+                AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(
+                        createDefaultDescriptor());
+
+        AudioDeviceAttributes attributes =
+                new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
+                        AudioDeviceInfo.TYPE_HDMI_ARC, "myAddress", "myName", new ArrayList<>(),
+                        new ArrayList<>(Arrays.asList(audioDescriptor1, audioDescriptor2)));
+        AudioPort port = AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(
+                attributes);
+        assertEquals("myName", port.name);
+        assertEquals(2, port.extraAudioDescriptors.length);
+        assertEquals(AudioStandard.EDID, port.extraAudioDescriptors[0].standard);
+        assertEquals(AudioEncapsulationType.IEC61937,
+                port.extraAudioDescriptors[0].encapsulationType);
+        assertTrue(Arrays.equals(new byte[]{0x05, 0x18, 0x4A},
+                port.extraAudioDescriptors[0].audioDescriptor));
+        assertEquals(AudioStandard.NONE, port.extraAudioDescriptors[1].standard);
+        assertEquals(AudioEncapsulationType.NONE,
+                port.extraAudioDescriptors[1].encapsulationType);
+        assertTrue(Arrays.equals(new byte[]{},
+                port.extraAudioDescriptors[1].audioDescriptor));
+        assertEquals("myAddress", port.ext.getDevice().device.address.getId());
+        assertEquals(AudioDeviceDescription.CONNECTION_HDMI_ARC,
+                port.ext.getDevice().device.type.connection);
+        assertEquals(AudioDeviceType.OUT_DEVICE, port.ext.getDevice().device.type.type);
+    }
+
     private static AudioFormatDescription createPcm16FormatAidl() {
         final AudioFormatDescription aidl = new AudioFormatDescription();
         aidl.type = AudioFormatType.PCM;
         aidl.pcm = PcmType.INT_16_BIT;
         return aidl;
     }
+
+    private static ExtraAudioDescriptor createDefaultDescriptor() {
+        ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
+        extraDescriptor.standard = AudioStandard.NONE;
+        extraDescriptor.encapsulationType = AudioEncapsulationType.NONE;
+        extraDescriptor.audioDescriptor = new byte[]{};
+        return extraDescriptor;
+    }
+
+    private static ExtraAudioDescriptor createEncapsulationDescriptor(byte[] audioDescriptor) {
+        ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
+        extraDescriptor.standard = AudioStandard.EDID;
+        extraDescriptor.encapsulationType = AudioEncapsulationType.IEC61937;
+        extraDescriptor.audioDescriptor = audioDescriptor;
+        return extraDescriptor;
+    }
 }
diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp
index 54538d9..6652780 100644
--- a/packages/ConnectivityT/framework-t/Android.bp
+++ b/packages/ConnectivityT/framework-t/Android.bp
@@ -158,8 +158,6 @@
     name: "framework-connectivity-tiramisu-sources",
     srcs: [
         ":framework-connectivity-ethernet-sources",
-        ":framework-connectivity-ipsec-sources",
-        ":framework-connectivity-netstats-sources",
     ],
     visibility: ["//frameworks/base"],
 }
@@ -167,6 +165,8 @@
 filegroup {
     name: "framework-connectivity-tiramisu-updatable-sources",
     srcs: [
+        ":framework-connectivity-ipsec-sources",
+        ":framework-connectivity-netstats-sources",
         ":framework-connectivity-nsd-sources",
         ":framework-connectivity-tiramisu-internal-sources",
     ],
@@ -194,15 +194,12 @@
         "jni/onload.cpp",
     ],
     shared_libs: [
+        "libandroid",
         "liblog",
-    ],
-    static_libs: [
-        "libnativehelper_compat_libc++",
+        "libnativehelper",
     ],
     stl: "none",
     apex_available: [
         "com.android.tethering",
-        // TODO: remove when ConnectivityT moves to APEX.
-        "//apex_available:platform",
     ],
 }
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 5ce7e59..0414bb7 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -27,7 +27,6 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.annotation.TestApi;
 import android.annotation.WorkerThread;
 import android.app.usage.NetworkStats.Bucket;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -192,9 +191,13 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Set poll force flag to indicate that calling any subsequent query method will force a stats
+     * poll.
+     * @hide
+     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    @TestApi
+    @SystemApi(client = MODULE_LIBRARIES)
     public void setPollForce(boolean pollForce) {
         if (pollForce) {
             mFlags |= FLAG_POLL_FORCE;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
index 630f902e..9bffbfb 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.app.SystemServiceRegistry;
+import android.app.usage.NetworkStatsManager;
 import android.content.Context;
 import android.net.nsd.INsdManager;
 import android.net.nsd.NsdManager;
@@ -48,5 +49,24 @@
                     return new NsdManager(context, service);
                 }
         );
+
+        SystemServiceRegistry.registerContextAwareService(
+                Context.IPSEC_SERVICE,
+                IpSecManager.class,
+                (context, serviceBinder) -> {
+                    IIpSecService service = IIpSecService.Stub.asInterface(serviceBinder);
+                    return new IpSecManager(context, service);
+                }
+        );
+
+        SystemServiceRegistry.registerContextAwareService(
+                Context.NETWORK_STATS_SERVICE,
+                NetworkStatsManager.class,
+                (context, serviceBinder) -> {
+                    INetworkStatsService service =
+                            INetworkStatsService.Stub.asInterface(serviceBinder);
+                    return new NetworkStatsManager(context, service);
+                }
+        );
     }
 }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index f472d56..1f67f6d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -19,12 +19,14 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.RemoteException;
 
@@ -358,11 +360,43 @@
         return proxy;
     }
 
-    private void updateConfiguration(
+    /**
+     * Updates the configuration of an automotive device's ethernet network.
+     *
+     * The {@link EthernetNetworkUpdateRequest} {@code request} argument describes how to update the
+     * configuration for this network.
+     * Use {@link StaticIpConfiguration.Builder} to build a {@code StaticIpConfiguration} object for
+     * this network to put inside the {@code request}.
+     * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities}
+     * object for this network to put inside the {@code request}.
+     *
+     * If non-null, the listener will be called exactly once after this is called, unless
+     * a synchronous exception was thrown.
+     *
+     * @param iface the name of the interface to act upon.
+     * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's
+     *                {@link StaticIpConfiguration} and {@link NetworkCapabilities} values.
+     * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
+     * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+     * @throws SecurityException if the process doesn't hold
+     *                          {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
+     * @throws UnsupportedOperationException if called on a non-automotive device or on an
+     *                                       unsupported interface.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
+    @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
+    public void updateConfiguration(
             @NonNull String iface,
             @NonNull EthernetNetworkUpdateRequest request,
             @Nullable @CallbackExecutor Executor executor,
             @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+        Objects.requireNonNull(iface, "iface must be non-null");
+        Objects.requireNonNull(request, "request must be non-null");
         final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
                 executor, listener);
         try {
@@ -372,10 +406,34 @@
         }
     }
 
-    private void connectNetwork(
+    /**
+     * Set an ethernet network's link state up.
+     *
+     * When the link is successfully turned up, the listener will be called with the resulting
+     * network. If any error or unexpected condition happens while the system tries to turn the
+     * interface up, the listener will be called with an appropriate exception.
+     * The listener is guaranteed to be called exactly once for each call to this method, but this
+     * may take an unbounded amount of time depending on the actual network conditions.
+     *
+     * @param iface the name of the interface to act upon.
+     * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
+     * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+     * @throws SecurityException if the process doesn't hold
+     *                          {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
+     * @throws UnsupportedOperationException if called on a non-automotive device.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
+    @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
+    public void connectNetwork(
             @NonNull String iface,
             @Nullable @CallbackExecutor Executor executor,
             @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+        Objects.requireNonNull(iface, "iface must be non-null");
         final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
                 executor, listener);
         try {
@@ -385,10 +443,33 @@
         }
     }
 
-    private void disconnectNetwork(
+    /**
+     * Set an ethernet network's link state down.
+     *
+     * When the link is successfully turned down, the listener will be called with the network that
+     * was torn down, if any. If any error or unexpected condition happens while the system tries to
+     * turn the interface down, the listener will be called with an appropriate exception.
+     * The listener is guaranteed to be called exactly once for each call to this method.
+     *
+     * @param iface the name of the interface to act upon.
+     * @param executor an {@link Executor} to execute the listener on. Optional if listener is null.
+     * @param listener an optional {@link BiConsumer} to listen for completion of the operation.
+     * @throws SecurityException if the process doesn't hold
+     *                          {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}.
+     * @throws UnsupportedOperationException if called on a non-automotive device.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
+    @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
+    public void disconnectNetwork(
             @NonNull String iface,
             @Nullable @CallbackExecutor Executor executor,
             @Nullable BiConsumer<Network, EthernetNetworkManagementException> listener) {
+        Objects.requireNonNull(iface, "iface must be non-null");
         final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener(
                 executor, listener);
         try {
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java
index a35f28e..a69cc55 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java
@@ -17,12 +17,14 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.util.Objects;
 
 /** @hide */
+@SystemApi
 public final class EthernetNetworkManagementException
         extends RuntimeException implements Parcelable {
 
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
index 4d229d2..e879e40 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
@@ -17,12 +17,14 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.util.Objects;
 
 /** @hide */
+@SystemApi
 public final class EthernetNetworkUpdateRequest implements Parcelable {
     @NonNull
     private final StaticIpConfiguration mIpConfig;
@@ -39,7 +41,6 @@
         return new NetworkCapabilities(mNetworkCapabilities);
     }
 
-    /** @hide */
     public EthernetNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig,
             @NonNull final NetworkCapabilities networkCapabilities) {
         Objects.requireNonNull(ipConfig);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
index 56faa52..4ebaf2b 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java
@@ -184,14 +184,14 @@
     public void dumpDebug(ProtoOutputStream proto, long tag) {
         final long start = proto.start(tag);
 
-        proto.write(NetworkIdentityProto.TYPE, mType);
+        proto.write(NetworkIdentityProto.TYPE_FIELD_NUMBER, mType);
 
         // TODO: dump mRatType as well.
 
-        proto.write(NetworkIdentityProto.ROAMING, mRoaming);
-        proto.write(NetworkIdentityProto.METERED, mMetered);
-        proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork);
-        proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged);
+        proto.write(NetworkIdentityProto.ROAMING_FIELD_NUMBER, mRoaming);
+        proto.write(NetworkIdentityProto.METERED_FIELD_NUMBER, mMetered);
+        proto.write(NetworkIdentityProto.DEFAULT_NETWORK_FIELD_NUMBER, mDefaultNetwork);
+        proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK_FIELD_NUMBER, mOemManaged);
 
         proto.end(start);
     }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java
index dfa347f..2236d70 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java
@@ -212,7 +212,7 @@
         final long start = proto.start(tag);
 
         for (NetworkIdentity ident : this) {
-            ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES);
+            ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES_FIELD_NUMBER);
         }
 
         proto.end(start);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
index 735c44d..67d48f0 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
@@ -732,19 +732,19 @@
         final long start = proto.start(tag);
 
         for (Key key : getSortedKeys()) {
-            final long startStats = proto.start(NetworkStatsCollectionProto.STATS);
+            final long startStats = proto.start(NetworkStatsCollectionProto.STATS_FIELD_NUMBER);
 
             // Key
-            final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY);
-            key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY);
-            proto.write(NetworkStatsCollectionKeyProto.UID, key.uid);
-            proto.write(NetworkStatsCollectionKeyProto.SET, key.set);
-            proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag);
+            final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY_FIELD_NUMBER);
+            key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY_FIELD_NUMBER);
+            proto.write(NetworkStatsCollectionKeyProto.UID_FIELD_NUMBER, key.uid);
+            proto.write(NetworkStatsCollectionKeyProto.SET_FIELD_NUMBER, key.set);
+            proto.write(NetworkStatsCollectionKeyProto.TAG_FIELD_NUMBER, key.tag);
             proto.end(startKey);
 
             // Value
             final NetworkStatsHistory history = mStats.get(key);
-            history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY);
+            history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY_FIELD_NUMBER);
             proto.end(startStats);
         }
 
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
index 78c1370..822a16e 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java
@@ -915,17 +915,18 @@
     public void dumpDebug(ProtoOutputStream proto, long tag) {
         final long start = proto.start(tag);
 
-        proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
+        proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS_FIELD_NUMBER, bucketDuration);
 
         for (int i = 0; i < bucketCount; i++) {
-            final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
+            final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS_FIELD_NUMBER);
 
-            proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
-            dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
+            proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS_FIELD_NUMBER,
+                    bucketStart[i]);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES_FIELD_NUMBER, rxBytes, i);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS_FIELD_NUMBER, rxPackets, i);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES_FIELD_NUMBER, txBytes, i);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS_FIELD_NUMBER, txPackets, i);
+            dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS_FIELD_NUMBER, operations, i);
 
             proto.end(startBucket);
         }
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
index 9b58b01..7b5afd7 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
@@ -79,7 +79,8 @@
             MATCH_WIFI,
             MATCH_ETHERNET,
             MATCH_BLUETOOTH,
-            MATCH_CARRIER
+            MATCH_PROXY,
+            MATCH_CARRIER,
     })
     public @interface TemplateMatchRule{}
 
@@ -104,9 +105,8 @@
     /** Match rule to match bluetooth networks. */
     public static final int MATCH_BLUETOOTH = 8;
     /**
-     * Match rule to match networks with {@link Connectivity#TYPE_PROXY} as the legacy network type.
-     *
-     * @hide
+     * Match rule to match networks with {@link ConnectivityManager#TYPE_PROXY} as the legacy
+     * network type.
      */
     public static final int MATCH_PROXY = 9;
     /**
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
index 0f21e55..512fbce 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
@@ -16,6 +16,9 @@
 
 package android.net.nsd;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
@@ -23,15 +26,22 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkRequest;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Objects;
@@ -278,9 +288,180 @@
     private final SparseArray mListenerMap = new SparseArray();
     private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>();
     private final Object mMapLock = new Object();
+    // Map of listener key sent by client -> per-network discovery tracker
+    @GuardedBy("mPerNetworkDiscoveryMap")
+    private final ArrayMap<Integer, PerNetworkDiscoveryTracker>
+            mPerNetworkDiscoveryMap = new ArrayMap<>();
 
     private final ServiceHandler mHandler;
 
+    private class PerNetworkDiscoveryTracker {
+        final String mServiceType;
+        final int mProtocolType;
+        final DiscoveryListener mBaseListener;
+        final ArrayMap<Network, DelegatingDiscoveryListener> mPerNetworkListeners =
+                new ArrayMap<>();
+
+        final NetworkCallback mNetworkCb = new NetworkCallback() {
+            @Override
+            public void onAvailable(@NonNull Network network) {
+                final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener(
+                        network, mBaseListener);
+                mPerNetworkListeners.put(network, wrappedListener);
+                discoverServices(mServiceType, mProtocolType, network, wrappedListener);
+            }
+
+            @Override
+            public void onLost(@NonNull Network network) {
+                final DelegatingDiscoveryListener listener = mPerNetworkListeners.get(network);
+                if (listener == null) return;
+                listener.notifyAllServicesLost();
+                // Listener will be removed from map in discovery stopped callback
+                stopServiceDiscovery(listener);
+            }
+        };
+
+        // Accessed from mHandler
+        private boolean mStopRequested;
+
+        public void start(@NonNull NetworkRequest request) {
+            final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+            cm.registerNetworkCallback(request, mNetworkCb, mHandler);
+            mHandler.post(() -> mBaseListener.onDiscoveryStarted(mServiceType));
+        }
+
+        /**
+         * Stop discovery on all networks tracked by this class.
+         *
+         * This will request all underlying listeners to stop, and the last one to stop will call
+         * onDiscoveryStopped or onStopDiscoveryFailed.
+         *
+         * Must be called on the handler thread.
+         */
+        public void requestStop() {
+            mHandler.post(() -> {
+                mStopRequested = true;
+                final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+                cm.unregisterNetworkCallback(mNetworkCb);
+                if (mPerNetworkListeners.size() == 0) {
+                    mBaseListener.onDiscoveryStopped(mServiceType);
+                    return;
+                }
+                for (int i = 0; i < mPerNetworkListeners.size(); i++) {
+                    final DelegatingDiscoveryListener listener = mPerNetworkListeners.valueAt(i);
+                    stopServiceDiscovery(listener);
+                }
+            });
+        }
+
+        private PerNetworkDiscoveryTracker(String serviceType, int protocolType,
+                DiscoveryListener baseListener) {
+            mServiceType = serviceType;
+            mProtocolType = protocolType;
+            mBaseListener = baseListener;
+        }
+
+        /**
+         * Subset of NsdServiceInfo that is tracked to generate service lost notifications when a
+         * network is lost.
+         *
+         * Service lost notifications only contain service name, type and network, so only track
+         * that information (Network is known from the listener). This also implements
+         * equals/hashCode for usage in maps.
+         */
+        private class TrackedNsdInfo {
+            private final String mServiceName;
+            private final String mServiceType;
+            TrackedNsdInfo(NsdServiceInfo info) {
+                mServiceName = info.getServiceName();
+                mServiceType = info.getServiceType();
+            }
+
+            @Override
+            public int hashCode() {
+                return Objects.hash(mServiceName, mServiceType);
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (!(obj instanceof TrackedNsdInfo)) return false;
+                final TrackedNsdInfo other = (TrackedNsdInfo) obj;
+                return Objects.equals(mServiceName, other.mServiceName)
+                        && Objects.equals(mServiceType, other.mServiceType);
+            }
+        }
+
+        private class DelegatingDiscoveryListener implements DiscoveryListener {
+            private final Network mNetwork;
+            private final DiscoveryListener mWrapped;
+            private final ArraySet<TrackedNsdInfo> mFoundInfo = new ArraySet<>();
+
+            private DelegatingDiscoveryListener(Network network, DiscoveryListener listener) {
+                mNetwork = network;
+                mWrapped = listener;
+            }
+
+            void notifyAllServicesLost() {
+                for (int i = 0; i < mFoundInfo.size(); i++) {
+                    final TrackedNsdInfo trackedInfo = mFoundInfo.valueAt(i);
+                    final NsdServiceInfo serviceInfo = new NsdServiceInfo(
+                            trackedInfo.mServiceName, trackedInfo.mServiceType);
+                    serviceInfo.setNetwork(mNetwork);
+                    mWrapped.onServiceLost(serviceInfo);
+                }
+            }
+
+            @Override
+            public void onStartDiscoveryFailed(String serviceType, int errorCode) {
+                // The delegated listener is used when NsdManager takes care of starting/stopping
+                // discovery on multiple networks. Failure to start on one network is not a global
+                // failure to be reported up, as other networks may succeed: just log.
+                Log.e(TAG, "Failed to start discovery for " + serviceType + " on " + mNetwork
+                        + " with code " + errorCode);
+                mPerNetworkListeners.remove(mNetwork);
+            }
+
+            @Override
+            public void onDiscoveryStarted(String serviceType) {
+                // Wrapped listener was called upon registration, it is not called for discovery
+                // on each network
+            }
+
+            @Override
+            public void onStopDiscoveryFailed(String serviceType, int errorCode) {
+                Log.e(TAG, "Failed to stop discovery for " + serviceType + " on " + mNetwork
+                        + " with code " + errorCode);
+                mPerNetworkListeners.remove(mNetwork);
+                if (mStopRequested && mPerNetworkListeners.size() == 0) {
+                    // Do not report onStopDiscoveryFailed when some underlying listeners failed:
+                    // this does not mean that all listeners did, and onStopDiscoveryFailed is not
+                    // actionable anyway. Just report that discovery stopped.
+                    mWrapped.onDiscoveryStopped(serviceType);
+                }
+            }
+
+            @Override
+            public void onDiscoveryStopped(String serviceType) {
+                mPerNetworkListeners.remove(mNetwork);
+                if (mStopRequested && mPerNetworkListeners.size() == 0) {
+                    mWrapped.onDiscoveryStopped(serviceType);
+                }
+            }
+
+            @Override
+            public void onServiceFound(NsdServiceInfo serviceInfo) {
+                mFoundInfo.add(new TrackedNsdInfo(serviceInfo));
+                mWrapped.onServiceFound(serviceInfo);
+            }
+
+            @Override
+            public void onServiceLost(NsdServiceInfo serviceInfo) {
+                mFoundInfo.remove(new TrackedNsdInfo(serviceInfo));
+                mWrapped.onServiceLost(serviceInfo);
+            }
+        }
+    }
+
     /**
      * Create a new Nsd instance. Applications use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -634,6 +815,14 @@
     }
 
     /**
+     * Same as {@link #discoverServices(String, int, Network, DiscoveryListener)} with a null
+     * {@link Network}.
+     */
+    public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
+        discoverServices(serviceType, protocolType, (Network) null, listener);
+    }
+
+    /**
      * Initiate service discovery to browse for instances of a service type. Service discovery
      * consumes network bandwidth and will continue until the application calls
      * {@link #stopServiceDiscovery}.
@@ -657,11 +846,13 @@
      * @param serviceType The service type being discovered. Examples include "_http._tcp" for
      * http services or "_ipp._tcp" for printers
      * @param protocolType The service discovery protocol
+     * @param network Network to discover services on, or null to discover on all available networks
      * @param listener  The listener notifies of a successful discovery and is used
      * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
      * Cannot be null. Cannot be in use for an active service discovery.
      */
-    public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
+    public void discoverServices(@NonNull String serviceType, int protocolType,
+            @Nullable Network network, @NonNull DiscoveryListener listener) {
         if (TextUtils.isEmpty(serviceType)) {
             throw new IllegalArgumentException("Service type cannot be empty");
         }
@@ -669,6 +860,7 @@
 
         NsdServiceInfo s = new NsdServiceInfo();
         s.setServiceType(serviceType);
+        s.setNetwork(network);
 
         int key = putListener(listener, s);
         try {
@@ -679,6 +871,67 @@
     }
 
     /**
+     * Initiate service discovery to browse for instances of a service type. Service discovery
+     * consumes network bandwidth and will continue until the application calls
+     * {@link #stopServiceDiscovery}.
+     *
+     * <p> The function call immediately returns after sending a request to start service
+     * discovery to the framework. The application is notified of a success to initiate
+     * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure
+     * through {@link DiscoveryListener#onStartDiscoveryFailed}.
+     *
+     * <p> Upon successful start, application is notified when a service is found with
+     * {@link DiscoveryListener#onServiceFound} or when a service is lost with
+     * {@link DiscoveryListener#onServiceLost}.
+     *
+     * <p> Upon failure to start, service discovery is not active and application does
+     * not need to invoke {@link #stopServiceDiscovery}
+     *
+     * <p> The application should call {@link #stopServiceDiscovery} when discovery of this
+     * service type is no longer required, and/or whenever the application is paused or
+     * stopped.
+     *
+     * <p> During discovery, new networks may connect or existing networks may disconnect - for
+     * example if wifi is reconnected. When a service was found on a network that disconnects,
+     * {@link DiscoveryListener#onServiceLost} will be called. If a new network connects that
+     * matches the {@link NetworkRequest}, {@link DiscoveryListener#onServiceFound} will be called
+     * for services found on that network. Applications that do not want to track networks
+     * themselves are encouraged to use this method instead of other overloads of
+     * {@code discoverServices}, as they will receive proper notifications when a service becomes
+     * available or unavailable due to network changes.
+     *
+     * @param serviceType The service type being discovered. Examples include "_http._tcp" for
+     * http services or "_ipp._tcp" for printers
+     * @param protocolType The service discovery protocol
+     * @param networkRequest Request specifying networks that should be considered when discovering
+     * @param listener  The listener notifies of a successful discovery and is used
+     * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
+     * Cannot be null. Cannot be in use for an active service discovery.
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+    public void discoverServices(@NonNull String serviceType, int protocolType,
+            @NonNull NetworkRequest networkRequest, @NonNull DiscoveryListener listener) {
+        if (TextUtils.isEmpty(serviceType)) {
+            throw new IllegalArgumentException("Service type cannot be empty");
+        }
+        Objects.requireNonNull(networkRequest, "NetworkRequest cannot be null");
+        checkProtocol(protocolType);
+
+        NsdServiceInfo s = new NsdServiceInfo();
+        s.setServiceType(serviceType);
+
+        final int baseListenerKey = putListener(listener, s);
+
+        final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker(
+                serviceType, protocolType, listener);
+
+        synchronized (mPerNetworkDiscoveryMap) {
+            mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo);
+            discoveryInfo.start(networkRequest);
+        }
+    }
+
+    /**
      * Stop service discovery initiated with {@link #discoverServices}.  An active service
      * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted}
      * and it stays active until the application invokes a stop service discovery. A successful
@@ -696,6 +949,14 @@
      */
     public void stopServiceDiscovery(DiscoveryListener listener) {
         int id = getListenerKey(listener);
+        // If this is a PerNetworkDiscovery request, handle it as such
+        synchronized (mPerNetworkDiscoveryMap) {
+            final PerNetworkDiscoveryTracker info = mPerNetworkDiscoveryMap.get(id);
+            if (info != null) {
+                info.requestStop();
+                return;
+            }
+        }
         try {
             mService.stopDiscovery(id);
         } catch (RemoteException e) {
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
index 0946499..8506db1 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
@@ -17,7 +17,9 @@
 package android.net.nsd;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.net.Network;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -49,6 +51,9 @@
 
     private int mPort;
 
+    @Nullable
+    private Network mNetwork;
+
     public NsdServiceInfo() {
     }
 
@@ -307,18 +312,37 @@
         return txtRecord;
     }
 
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
+    /**
+     * Get the network where the service can be found.
+     *
+     * This is never null if this {@link NsdServiceInfo} was obtained from
+     * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}.
+     */
+    @Nullable
+    public Network getNetwork() {
+        return mNetwork;
+    }
 
+    /**
+     * Set the network where the service can be found.
+     * @param network The network, or null to search for, or to announce, the service on all
+     *                connected networks.
+     */
+    public void setNetwork(@Nullable Network network) {
+        mNetwork = network;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
         sb.append("name: ").append(mServiceName)
                 .append(", type: ").append(mServiceType)
                 .append(", host: ").append(mHost)
-                .append(", port: ").append(mPort);
+                .append(", port: ").append(mPort)
+                .append(", network: ").append(mNetwork);
 
         byte[] txtRecord = getTxtRecord();
-        if (txtRecord != null) {
-            sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
-        }
+        sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
         return sb.toString();
     }
 
@@ -352,6 +376,8 @@
             }
             dest.writeString(key);
         }
+
+        dest.writeParcelable(mNetwork, 0);
     }
 
     /** Implement the Parcelable interface */
@@ -381,6 +407,7 @@
                     }
                     info.mTxtRecord.put(in.readString(), valueArray);
                 }
+                info.mNetwork = in.readParcelable(null, Network.class);
                 return info;
             }
 
diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp
index 24bc91d..5100e7c 100644
--- a/packages/ConnectivityT/service/Android.bp
+++ b/packages/ConnectivityT/service/Android.bp
@@ -28,6 +28,11 @@
         "src/com/android/server/net/NetworkStats*.java",
         "src/com/android/server/net/BpfInterfaceMapUpdater.java",
         "src/com/android/server/net/InterfaceMapValue.java",
+        "src/com/android/server/net/CookieTagMapKey.java",
+        "src/com/android/server/net/CookieTagMapValue.java",
+        "src/com/android/server/net/StatsMapKey.java",
+        "src/com/android/server/net/StatsMapValue.java",
+        "src/com/android/server/net/UidStatsMapKey.java",
     ],
     path: "src",
     visibility: [
@@ -35,6 +40,30 @@
     ],
 }
 
+// For test code only.
+filegroup {
+    name: "lib_networkStatsFactory_native",
+    srcs: [
+        "jni/com_android_server_net_NetworkStatsFactory.cpp",
+    ],
+    path: "jni",
+    visibility: [
+        "//packages/modules/Connectivity:__subpackages__",
+    ],
+}
+
+filegroup {
+    name: "services.connectivity-netstats-jni-sources",
+    srcs: [
+        "jni/com_android_server_net_NetworkStatsFactory.cpp",
+        "jni/com_android_server_net_NetworkStatsService.cpp",
+    ],
+    path: "jni",
+    visibility: [
+        "//packages/modules/Connectivity:__subpackages__",
+    ],
+}
+
 // Nsd related libraries.
 
 filegroup {
@@ -83,8 +112,6 @@
     name: "services.connectivity-tiramisu-sources",
     srcs: [
         ":services.connectivity-ethernet-sources",
-        ":services.connectivity-ipsec-sources",
-        ":services.connectivity-netstats-sources",
     ],
     path: "src",
     visibility: ["//frameworks/base/services/core"],
@@ -93,6 +120,8 @@
 filegroup {
     name: "services.connectivity-tiramisu-updatable-sources",
     srcs: [
+        ":services.connectivity-ipsec-sources",
+        ":services.connectivity-netstats-sources",
         ":services.connectivity-nsd-sources",
     ],
     path: "src",
diff --git a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp
similarity index 100%
rename from services/core/jni/com_android_server_net_NetworkStatsFactory.cpp
rename to packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp
similarity index 100%
rename from services/core/jni/com_android_server_net_NetworkStatsService.cpp
rename to packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp
diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
index 179d945..4bc40ea 100644
--- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
@@ -1008,16 +1008,10 @@
      *
      * @param context Binder context for this service
      */
-    private IpSecService(Context context) {
+    public IpSecService(Context context) {
         this(context, new Dependencies());
     }
 
-    static IpSecService create(Context context)
-            throws InterruptedException {
-        final IpSecService service = new IpSecService(context);
-        return service;
-    }
-
     @NonNull
     private AppOpsManager getAppOpsManager() {
         AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
@@ -1054,26 +1048,6 @@
         }
     }
 
-    /** Called by system server when system is ready. */
-    public void systemReady() {
-        if (isNetdAlive()) {
-            Log.d(TAG, "IpSecService is ready");
-        } else {
-            Log.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!");
-        }
-    }
-
-    synchronized boolean isNetdAlive() {
-        try {
-            if (mNetd == null) {
-                return false;
-            }
-            return mNetd.isAlive();
-        } catch (RemoteException re) {
-            return false;
-        }
-    }
-
     /**
      * Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be
      * a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1.
@@ -1896,7 +1870,6 @@
         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
 
         pw.println("IpSecService dump:");
-        pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
         pw.println();
 
         pw.println("mUserResourceTracker:");
diff --git a/packages/ConnectivityT/service/src/com/android/server/NsdService.java b/packages/ConnectivityT/service/src/com/android/server/NsdService.java
index 497107d..ddf6d2c 100644
--- a/packages/ConnectivityT/service/src/com/android/server/NsdService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/NsdService.java
@@ -19,6 +19,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
 import android.net.nsd.INsdManager;
 import android.net.nsd.INsdManagerCallback;
 import android.net.nsd.INsdServiceConnector;
@@ -44,6 +47,9 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.concurrent.CountDownLatch;
@@ -60,6 +66,7 @@
 
     private static final boolean DBG = true;
     private static final long CLEANUP_DELAY_MS = 10000;
+    private static final int IFACE_IDX_ANY = 0;
 
     private final Context mContext;
     private final NsdStateMachine mNsdStateMachine;
@@ -297,7 +304,7 @@
 
                         maybeStartDaemon();
                         id = getUniqueId();
-                        if (discoverServices(id, args.serviceInfo.getServiceType())) {
+                        if (discoverServices(id, args.serviceInfo)) {
                             if (DBG) {
                                 Log.d(TAG, "Discover " + msg.arg2 + " " + id
                                         + args.serviceInfo.getServiceType());
@@ -430,13 +437,38 @@
                 }
                 switch (code) {
                     case NativeResponseCode.SERVICE_FOUND:
-                        /* NNN uniqueId serviceName regType domain */
+                        /* NNN uniqueId serviceName regType domain interfaceIdx netId */
                         servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
+                        final int foundNetId;
+                        try {
+                            foundNetId = Integer.parseInt(cooked[6]);
+                        } catch (NumberFormatException e) {
+                            Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]);
+                            break;
+                        }
+                        if (foundNetId == 0L) {
+                            // Ignore services that do not have a Network: they are not usable
+                            // by apps, as they would need privileged permissions to use
+                            // interfaces that do not have an associated Network.
+                            break;
+                        }
+                        servInfo.setNetwork(new Network(foundNetId));
                         clientInfo.onServiceFound(clientId, servInfo);
                         break;
                     case NativeResponseCode.SERVICE_LOST:
-                        /* NNN uniqueId serviceName regType domain */
+                        /* NNN uniqueId serviceName regType domain interfaceIdx netId */
+                        final int lostNetId;
+                        try {
+                            lostNetId = Integer.parseInt(cooked[6]);
+                        } catch (NumberFormatException e) {
+                            Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]);
+                            break;
+                        }
                         servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
+                        // The network could be null if it was torn down when the service is lost
+                        // TODO: avoid returning null in that case, possibly by remembering found
+                        // services on the same interface index and their network at the time
+                        servInfo.setNetwork(lostNetId == 0 ? null : new Network(lostNetId));
                         clientInfo.onServiceLost(clientId, servInfo);
                         break;
                     case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
@@ -461,7 +493,7 @@
                         /* NNN regId errorCode */
                         break;
                     case NativeResponseCode.SERVICE_RESOLVED:
-                        /* NNN resolveId fullName hostName port txtlen txtdata */
+                        /* NNN resolveId fullName hostName port txtlen txtdata interfaceIdx */
                         int index = 0;
                         while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
                             if (cooked[2].charAt(index) == '\\') {
@@ -473,6 +505,7 @@
                             Log.e(TAG, "Invalid service found " + raw);
                             break;
                         }
+
                         String name = cooked[2].substring(0, index);
                         String rest = cooked[2].substring(index);
                         String type = rest.replace(".local.", "");
@@ -483,12 +516,13 @@
                         clientInfo.mResolvedService.setServiceType(type);
                         clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
                         clientInfo.mResolvedService.setTxtRecords(cooked[6]);
+                        // Network will be added after SERVICE_GET_ADDR_SUCCESS
 
                         stopResolveService(id);
                         removeRequestMap(clientId, id, clientInfo);
 
                         int id2 = getUniqueId();
-                        if (getAddrInfo(id2, cooked[3])) {
+                        if (getAddrInfo(id2, cooked[3], cooked[7] /* interfaceIdx */)) {
                             storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
                         } else {
                             clientInfo.onResolveServiceFailed(
@@ -513,12 +547,31 @@
                                 clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         break;
                     case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
-                        /* NNN resolveId hostname ttl addr */
+                        /* NNN resolveId hostname ttl addr interfaceIdx netId */
+                        Network network = null;
                         try {
-                            clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
+                            final int netId = Integer.parseInt(cooked[6]);
+                            network = netId == 0L ? null : new Network(netId);
+                        } catch (NumberFormatException e) {
+                            Log.wtf(TAG, "Invalid network in GET_ADDR_SUCCESS: " + cooked[6], e);
+                        }
+
+                        InetAddress serviceHost = null;
+                        try {
+                            serviceHost = InetAddress.getByName(cooked[4]);
+                        } catch (UnknownHostException e) {
+                            Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e);
+                        }
+
+                        // If the resolved service is on an interface without a network, consider it
+                        // as a failure: it would not be usable by apps as they would need
+                        // privileged permissions.
+                        if (network != null && serviceHost != null) {
+                            clientInfo.mResolvedService.setHost(serviceHost);
+                            clientInfo.mResolvedService.setNetwork(network);
                             clientInfo.onResolveServiceSucceeded(
                                     clientId, clientInfo.mResolvedService);
-                        } catch (java.net.UnknownHostException e) {
+                        } else {
                             clientInfo.onResolveServiceFailed(
                                     clientId, NsdManager.FAILURE_INTERNAL_ERROR);
                         }
@@ -815,8 +868,15 @@
         return mDaemon.execute("update", regId, t.size(), t.getRawData());
     }
 
-    private boolean discoverServices(int discoveryId, String serviceType) {
-        return mDaemon.execute("discover", discoveryId, serviceType);
+    private boolean discoverServices(int discoveryId, NsdServiceInfo serviceInfo) {
+        final Network network = serviceInfo.getNetwork();
+        final int discoverInterface = getNetworkInterfaceIndex(network);
+        if (network != null && discoverInterface == IFACE_IDX_ANY) {
+            Log.e(TAG, "Interface to discover service on not found");
+            return false;
+        }
+        return mDaemon.execute("discover", discoveryId, serviceInfo.getServiceType(),
+                discoverInterface);
     }
 
     private boolean stopServiceDiscovery(int discoveryId) {
@@ -824,17 +884,61 @@
     }
 
     private boolean resolveService(int resolveId, NsdServiceInfo service) {
-        String name = service.getServiceName();
-        String type = service.getServiceType();
-        return mDaemon.execute("resolve", resolveId, name, type, "local.");
+        final String name = service.getServiceName();
+        final String type = service.getServiceType();
+        final Network network = service.getNetwork();
+        final int resolveInterface = getNetworkInterfaceIndex(network);
+        if (network != null && resolveInterface == IFACE_IDX_ANY) {
+            Log.e(TAG, "Interface to resolve service on not found");
+            return false;
+        }
+        return mDaemon.execute("resolve", resolveId, name, type, "local.", resolveInterface);
+    }
+
+    /**
+     * Guess the interface to use to resolve or discover a service on a specific network.
+     *
+     * This is an imperfect guess, as for example the network may be gone or not yet fully
+     * registered. This is fine as failing is correct if the network is gone, and a client
+     * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also
+     * this is to support the legacy mdnsresponder implementation, which historically resolved
+     * services on an unspecified network.
+     */
+    private int getNetworkInterfaceIndex(Network network) {
+        if (network == null) return IFACE_IDX_ANY;
+
+        final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+        if (cm == null) {
+            Log.wtf(TAG, "No ConnectivityManager for resolveService");
+            return IFACE_IDX_ANY;
+        }
+        final LinkProperties lp = cm.getLinkProperties(network);
+        if (lp == null) return IFACE_IDX_ANY;
+
+        // Only resolve on non-stacked interfaces
+        final NetworkInterface iface;
+        try {
+            iface = NetworkInterface.getByName(lp.getInterfaceName());
+        } catch (SocketException e) {
+            Log.e(TAG, "Error querying interface", e);
+            return IFACE_IDX_ANY;
+        }
+
+        if (iface == null) {
+            Log.e(TAG, "Interface not found: " + lp.getInterfaceName());
+            return IFACE_IDX_ANY;
+        }
+
+        return iface.getIndex();
     }
 
     private boolean stopResolveService(int resolveId) {
         return mDaemon.execute("stop-resolve", resolveId);
     }
 
-    private boolean getAddrInfo(int resolveId, String hostname) {
-        return mDaemon.execute("getaddrinfo", resolveId, hostname);
+    private boolean getAddrInfo(int resolveId, String hostname, String interfaceIdx) {
+        // interfaceIdx is always obtained (as string) from the service resolved callback
+        return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceIdx);
     }
 
     private boolean stopGetAddrInfo(int resolveId) {
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java
new file mode 100644
index 0000000..443e5b3
--- /dev/null
+++ b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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.net;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * Key for cookie tag map.
+ */
+public class CookieTagMapKey extends Struct {
+    @Field(order = 0, type = Type.S64)
+    public final long socketCookie;
+
+    public CookieTagMapKey(final long socketCookie) {
+        this.socketCookie = socketCookie;
+    }
+}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java
new file mode 100644
index 0000000..93b9195
--- /dev/null
+++ b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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.net;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * Value for cookie tag map.
+ */
+public class CookieTagMapValue extends Struct {
+    @Field(order = 0, type = Type.U32)
+    public final long uid;
+
+    @Field(order = 1, type = Type.U32)
+    public final long tag;
+
+    public CookieTagMapValue(final long uid, final long tag) {
+        this.uid = uid;
+        this.tag = tag;
+    }
+}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
index 668d1cb..151c90d 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java
@@ -54,6 +54,10 @@
  * @hide
  */
 public class NetworkStatsFactory {
+    static {
+        System.loadLibrary("service-connectivity");
+    }
+
     private static final String TAG = "NetworkStatsFactory";
 
     private static final boolean USE_NATIVE_PARSING = true;
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
index c371f08..a006cd5 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java
@@ -471,9 +471,11 @@
     public void dumpDebugLocked(ProtoOutputStream proto, long tag) {
         final long start = proto.start(tag);
         if (mPending != null) {
-            proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
+            proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES_FIELD_NUMBER,
+                    mPending.getTotalBytes());
         }
-        getOrLoadCompleteLocked().dumpDebug(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
+        getOrLoadCompleteLocked().dumpDebug(proto,
+                NetworkStatsRecorderProto.COMPLETE_HISTORY_FIELD_NUMBER);
         proto.end(start);
     }
 
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index 9f3371b..7a5ba09 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -62,6 +62,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TargetApi;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.app.usage.NetworkStatsManager;
@@ -102,6 +103,7 @@
 import android.net.netstats.provider.INetworkStatsProviderCallback;
 import android.net.netstats.provider.NetworkStatsProvider;
 import android.os.Binder;
+import android.os.Build;
 import android.os.DropBoxManager;
 import android.os.Environment;
 import android.os.Handler;
@@ -169,7 +171,12 @@
  * Collect and persist detailed network statistics, and provide this data to
  * other system services.
  */
+@TargetApi(Build.VERSION_CODES.TIRAMISU)
 public class NetworkStatsService extends INetworkStatsService.Stub {
+    static {
+        System.loadLibrary("service-connectivity");
+    }
+
     static final String TAG = "NetworkStats";
     static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
     static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
@@ -2004,12 +2011,15 @@
 
         // TODO Right now it writes all history.  Should it limit to the "since-boot" log?
 
-        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces);
-        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces);
-        mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
-        mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
-        mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
-        mUidTagRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS);
+        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES_FIELD_NUMBER,
+                mActiveIfaces);
+        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES_FIELD_NUMBER,
+                mActiveUidIfaces);
+        mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS_FIELD_NUMBER);
+        mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS_FIELD_NUMBER);
+        mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS_FIELD_NUMBER);
+        mUidTagRecorder.dumpDebugLocked(proto,
+                NetworkStatsServiceDumpProto.UID_TAG_STATS_FIELD_NUMBER);
 
         proto.flush();
     }
@@ -2019,8 +2029,8 @@
         for (int i = 0; i < ifaces.size(); i++) {
             final long start = proto.start(tag);
 
-            proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i));
-            ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES);
+            proto.write(NetworkInterfaceProto.INTERFACE_FIELD_NUMBER, ifaces.keyAt(i));
+            ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES_FIELD_NUMBER);
 
             proto.end(start);
         }
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 5bba0b1..65ccd20 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -23,7 +23,9 @@
 import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE;
 
 import android.annotation.NonNull;
+import android.annotation.TargetApi;
 import android.content.Context;
+import android.os.Build;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyCallback;
 import android.telephony.TelephonyDisplayInfo;
@@ -43,6 +45,7 @@
 /**
  * Helper class that watches for events that are triggered per subscription.
  */
+@TargetApi(Build.VERSION_CODES.TIRAMISU)
 public class NetworkStatsSubscriptionsMonitor extends
         SubscriptionManager.OnSubscriptionsChangedListener {
 
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java
new file mode 100644
index 0000000..ea8d836
--- /dev/null
+++ b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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.net;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * Key for both stats maps.
+ */
+public class StatsMapKey extends Struct {
+    @Field(order = 0, type = Type.U32)
+    public final long uid;
+
+    @Field(order = 1, type = Type.U32)
+    public final long tag;
+
+    @Field(order = 2, type = Type.U32)
+    public final long counterSet;
+
+    @Field(order = 3, type = Type.U32)
+    public final long ifaceIndex;
+
+    public StatsMapKey(final long uid, final long tag, final long counterSet,
+            final long ifaceIndex) {
+        this.uid = uid;
+        this.tag = tag;
+        this.counterSet = counterSet;
+        this.ifaceIndex = ifaceIndex;
+    }
+}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java
new file mode 100644
index 0000000..48f26ce
--- /dev/null
+++ b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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.net;
+
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
+
+/**
+ * Value used for both stats maps and uid stats map.
+ */
+public class StatsMapValue extends Struct {
+    @Field(order = 0, type = Type.U63)
+    public final long rxPackets;
+
+    @Field(order = 1, type = Type.U63)
+    public final long rxBytes;
+
+    @Field(order = 2, type = Type.U63)
+    public final long txPackets;
+
+    @Field(order = 3, type = Type.U63)
+    public final long txBytes;
+
+    public StatsMapValue(final long rxPackets, final long rxBytes, final long txPackets,
+            final long txBytes) {
+        this.rxPackets = rxPackets;
+        this.rxBytes = rxBytes;
+        this.txPackets = txPackets;
+        this.txBytes = txBytes;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java b/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java
similarity index 61%
copy from services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java
copy to packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java
index 3c99a98..2849f94 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java
@@ -14,12 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.server.dreams;
+package com.android.server.net;
 
-import android.service.dreams.DreamService;
+import com.android.net.module.util.Struct;
+import com.android.net.module.util.Struct.Field;
+import com.android.net.module.util.Struct.Type;
 
 /**
- * Dream service implementation for unit testing.
+ * Key for uid stats map.
  */
-public class TestDreamService extends DreamService {
+public class UidStatsMapKey extends Struct {
+    @Field(order = 0, type = Type.U32)
+    public final long uid;
+
+    public UidStatsMapKey(final long uid) {
+        this.uid = uid;
+    }
 }
diff --git a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
index c8ddcc8..6940c39 100644
--- a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
+++ b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
@@ -27,14 +27,14 @@
         android:layout_gravity="center">
         <ImageView
             android:id="@+id/user_photo"
-            android:layout_width="@dimen/user_photo_size_in_profile_info_dialog"
-            android:layout_height="@dimen/user_photo_size_in_profile_info_dialog"
+            android:layout_width="@dimen/user_photo_size_in_user_info_dialog"
+            android:layout_height="@dimen/user_photo_size_in_user_info_dialog"
             android:contentDescription="@string/user_image_photo_selector"
             android:scaleType="fitCenter"/>
         <ImageView
             android:id="@+id/add_a_photo_icon"
-            android:layout_width="@dimen/add_a_photo_icon_size_in_profile_info_dialog"
-            android:layout_height="@dimen/add_a_photo_icon_size_in_profile_info_dialog"
+            android:layout_width="@dimen/add_a_photo_icon_size_in_user_info_dialog"
+            android:layout_height="@dimen/add_a_photo_icon_size_in_user_info_dialog"
             android:src="@drawable/add_a_photo_circled"
             android:layout_gravity="bottom|right" />
     </FrameLayout>
@@ -42,7 +42,7 @@
     <EditText
         android:id="@+id/user_name"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="@dimen/user_name_height_in_user_info_dialog"
         android:layout_gravity="center"
         android:minWidth="200dp"
         android:layout_marginStart="6dp"
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 120df76..e1bd9f7 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -99,8 +99,9 @@
     <dimen name="update_user_photo_popup_min_width">300dp</dimen>
 
     <dimen name="add_a_photo_circled_padding">6dp</dimen>
-    <dimen name="user_photo_size_in_profile_info_dialog">112dp</dimen>
-    <dimen name="add_a_photo_icon_size_in_profile_info_dialog">32dp</dimen>
+    <dimen name="user_photo_size_in_user_info_dialog">112dp</dimen>
+    <dimen name="add_a_photo_icon_size_in_user_info_dialog">32dp</dimen>
+    <dimen name="user_name_height_in_user_info_dialog">48sp</dimen>
 
     <integer name="avatar_picker_columns">3</integer>
     <dimen name="avatar_size_in_picker">96dp</dimen>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 15ca8cd..df19c67 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -223,7 +223,7 @@
     }
 
     public boolean supportsHighQualityAudio(BluetoothDevice device) {
-        BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
+        BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         if (bluetoothDevice == null) {
             return false;
         }
@@ -236,7 +236,7 @@
      */
     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
-        BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
+        BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         if (bluetoothDevice == null) {
             return false;
         }
@@ -262,7 +262,7 @@
     }
 
     public void setHighQualityAudioEnabled(BluetoothDevice device, boolean enabled) {
-        BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
+        BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         if (bluetoothDevice == null) {
             return;
         }
@@ -288,7 +288,7 @@
      */
     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
-        BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
+        BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
         int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
         if (bluetoothDevice == null || !supportsHighQualityAudio(device)
                 || getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index db6d41e..e203cba 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -144,20 +144,20 @@
     * @hide
     */
     public boolean connect(BluetoothDevice device) {
-       if (mService == null) {
-           return false;
-       }
-       return mService.connect(device);
+        if (mService == null) {
+            return false;
+        }
+        return mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
     }
 
     /*
     * @hide
     */
     public boolean disconnect(BluetoothDevice device) {
-       if (mService == null) {
-           return false;
-       }
-       return mService.disconnect(device);
+        if (mService == null) {
+            return false;
+        }
+        return mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
     }
 
     public int getConnectionStatus(BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index a781a62..035fafd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -16,6 +16,10 @@
 
 package com.android.settingslib.drawable;
 
+import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
+import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
+import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_USER_ICON;
+
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
@@ -38,9 +42,12 @@
 import android.graphics.Shader;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.UserHandle;
 
+import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.os.BuildCompat;
 
 import com.android.settingslib.R;
 
@@ -82,8 +89,23 @@
      * @return drawable containing just the badge
      */
     public static Drawable getManagedUserDrawable(Context context) {
-        return getDrawableForDisplayDensity
-                (context, com.android.internal.R.drawable.ic_corp_user_badge);
+        if (BuildCompat.isAtLeastT()) {
+            return getUpdatableManagedUserDrawable(context);
+        } else {
+            return getDrawableForDisplayDensity(
+                    context, com.android.internal.R.drawable.ic_corp_user_badge);
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+    private static Drawable getUpdatableManagedUserDrawable(Context context) {
+        DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+        return dpm.getDrawableForDensity(
+                WORK_PROFILE_USER_ICON,
+                SOLID_COLORED,
+                context.getResources().getDisplayMetrics().densityDpi,
+                /* default= */ () -> getDrawableForDisplayDensity(
+                        context, com.android.internal.R.drawable.ic_corp_user_badge));
     }
 
     private static Drawable getDrawableForDisplayDensity(
@@ -181,8 +203,7 @@
                     && dpm.getProfileOwnerOrDeviceOwnerSupervisionComponent(UserHandle.of(userId))
                             == null; // and has no supervisor
             if (isCorp) {
-                badge = getDrawableForDisplayDensity(
-                        context, com.android.internal.R.drawable.ic_corp_badge_case);
+                badge = getManagementBadge(context);
             }
         }
         return setBadge(badge);
@@ -192,16 +213,35 @@
      * Sets the managed badge to this user icon if the device has a device owner.
      */
     public UserIconDrawable setBadgeIfManagedDevice(Context context) {
+        DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
         Drawable badge = null;
-        boolean deviceOwnerExists = context.getSystemService(DevicePolicyManager.class)
-                .getDeviceOwnerComponentOnAnyUser() != null;
+        boolean deviceOwnerExists = dpm.getDeviceOwnerComponentOnAnyUser() != null;
         if (deviceOwnerExists) {
-            badge = getDrawableForDisplayDensity(
-                    context, com.android.internal.R.drawable.ic_corp_badge_case);
+            badge = getManagementBadge(context);
         }
         return setBadge(badge);
     }
 
+    private static Drawable getManagementBadge(Context context) {
+        if (BuildCompat.isAtLeastT()) {
+            return getUpdatableManagementBadge(context);
+        } else {
+            return getDrawableForDisplayDensity(
+                    context, com.android.internal.R.drawable.ic_corp_user_badge);
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+    private static Drawable getUpdatableManagementBadge(Context context) {
+        DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+        return dpm.getDrawableForDensity(
+                WORK_PROFILE_ICON,
+                SOLID_COLORED,
+                context.getResources().getDisplayMetrics().densityDpi,
+                /* default= */ () -> getDrawableForDisplayDensity(
+                        context, com.android.internal.R.drawable.ic_corp_badge_case));
+    }
+
     public void setBadgeRadius(float radius) {
         mBadgeRadius = radius;
         onBoundsChange(getBounds());
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index 6ef8d39..d179b82 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -26,6 +26,8 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -33,14 +35,21 @@
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.text.TextUtils;
+import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Xml;
 
 import com.android.settingslib.R;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
@@ -161,7 +170,7 @@
         PackageManager pm = mContext.getPackageManager();
         Intent dreamIntent = new Intent(DreamService.SERVICE_INTERFACE);
         List<ResolveInfo> resolveInfos = pm.queryIntentServices(dreamIntent,
-                PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA));
+                PackageManager.GET_META_DATA);
         List<DreamInfo> dreamInfos = new ArrayList<>(resolveInfos.size());
         for (ResolveInfo resolveInfo : resolveInfos) {
             final ComponentName componentName = getDreamComponentName(resolveInfo);
@@ -176,18 +185,15 @@
             dreamInfo.componentName = componentName;
             dreamInfo.isActive = dreamInfo.componentName.equals(activeDream);
 
-            final DreamService.DreamMetadata dreamMetadata = DreamService.getDreamMetadata(mContext,
-                    resolveInfo.serviceInfo);
-            if (dreamMetadata != null) {
-                dreamInfo.settingsComponentName = dreamMetadata.settingsActivity;
-                dreamInfo.previewImage = dreamMetadata.previewImage;
-            }
+            final DreamMetadata dreamMetadata = getDreamMetadata(pm, resolveInfo);
+            dreamInfo.settingsComponentName = dreamMetadata.mSettingsActivity;
+            dreamInfo.previewImage = dreamMetadata.mPreviewImage;
             if (dreamInfo.previewImage == null) {
                 dreamInfo.previewImage = mDreamPreviewDefault;
             }
             dreamInfos.add(dreamInfo);
         }
-        dreamInfos.sort(mComparator);
+        Collections.sort(dreamInfos, mComparator);
         return dreamInfos;
     }
 
@@ -477,6 +483,78 @@
         return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
     }
 
+    private static final class DreamMetadata {
+        @Nullable
+        Drawable mPreviewImage;
+        @Nullable
+        ComponentName mSettingsActivity;
+    }
+
+    @Nullable
+    private static TypedArray readMetadata(PackageManager pm, ServiceInfo serviceInfo) {
+        if (serviceInfo == null || serviceInfo.metaData == null) {
+            return null;
+        }
+        try (XmlResourceParser parser =
+                     serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA)) {
+            if (parser == null) {
+                Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " meta-data");
+                return null;
+            }
+            Resources res = pm.getResourcesForApplication(serviceInfo.applicationInfo);
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+            while (true) {
+                final int type = parser.next();
+                if (type == XmlPullParser.END_DOCUMENT || type == XmlPullParser.START_TAG) {
+                    break;
+                }
+            }
+            String nodeName = parser.getName();
+            if (!"dream".equals(nodeName)) {
+                Log.w(TAG, "Meta-data does not start with dream tag");
+                return null;
+            }
+            return res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream);
+        } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
+            Log.w(TAG, "Error parsing : " + serviceInfo.packageName, e);
+            return null;
+        }
+    }
+
+    private static ComponentName convertToComponentName(String flattenedString,
+            ServiceInfo serviceInfo) {
+        if (flattenedString == null) return null;
+
+        if (flattenedString.indexOf('/') < 0) {
+            flattenedString = serviceInfo.packageName + "/" + flattenedString;
+        }
+
+        ComponentName cn = ComponentName.unflattenFromString(flattenedString);
+
+        if (cn == null) return null;
+        if (!cn.getPackageName().equals(serviceInfo.packageName)) {
+            Log.w(TAG,
+                    "Inconsistent package name in component: " + cn.getPackageName()
+                            + ", should be: " + serviceInfo.packageName);
+            return null;
+        }
+
+        return cn;
+    }
+
+    private static DreamMetadata getDreamMetadata(PackageManager pm, ResolveInfo resolveInfo) {
+        DreamMetadata result = new DreamMetadata();
+        if (resolveInfo == null) return result;
+        TypedArray rawMetadata = readMetadata(pm, resolveInfo.serviceInfo);
+        if (rawMetadata == null) return result;
+        result.mSettingsActivity = convertToComponentName(rawMetadata.getString(
+                com.android.internal.R.styleable.Dream_settingsActivity), resolveInfo.serviceInfo);
+        result.mPreviewImage = rawMetadata.getDrawable(
+                com.android.internal.R.styleable.Dream_previewImage);
+        rawMetadata.recycle();
+        return result;
+    }
+
     private static void logd(String msg, Object... args) {
         if (DEBUG) {
             Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
index b0a647e..95f7ef4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
@@ -81,8 +81,8 @@
         when(mSubscriptionManager.isActiveSubscriptionId(SUB_ID)).thenReturn(false);
 
         final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
-        assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
-        assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isFalse();
+        assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue();
+        assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isFalse();
     }
 
     @Test
@@ -94,8 +94,8 @@
                 .thenReturn(new String[] {SUBSCRIBER_ID});
 
         final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
-        assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
-        assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isFalse();
+        assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue();
+        assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isFalse();
     }
 
     @Test
@@ -107,7 +107,7 @@
                 .thenReturn(new String[] {SUBSCRIBER_ID, SUBSCRIBER_ID_2});
 
         final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
-        assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
-        assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isTrue();
+        assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID)).isTrue();
+        assertThat(networkTemplate.getSubscriberIds().contains(SUBSCRIBER_ID_2)).isTrue();
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 00b5f50..a6bfc408b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -84,6 +84,7 @@
         Settings.System.RING_VIBRATION_INTENSITY,
         Settings.System.HAPTIC_FEEDBACK_INTENSITY,
         Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY,
+        Settings.System.HAPTIC_FEEDBACK_ENABLED,
         Settings.System.DISPLAY_COLOR_MODE_VENDOR_HINT, // must precede DISPLAY_COLOR_MODE
         Settings.System.DISPLAY_COLOR_MODE,
         Settings.System.ALARM_ALERT,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index 246466e..bbfab0b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -314,6 +314,7 @@
         VALIDATORS.put(Global.USER_PREFERRED_RESOLUTION_HEIGHT, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.USER_PREFERRED_RESOLUTION_WIDTH, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Global.Wearable.WET_MODE_ON, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.COOLDOWN_MODE_ON, BOOLEAN_VALIDATOR);
     }
 }
 
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 6bcb769..06712cc 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -124,6 +124,7 @@
         VALIDATORS.put(System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
         VALIDATORS.put(System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
         VALIDATORS.put(System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+        VALIDATORS.put(System.HAPTIC_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.RINGTONE, URI_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR);
         VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 13ae870..be25b47 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -594,6 +594,7 @@
                     Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
                     Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
                     Settings.Global.CLOCKWORK_HOME_READY,
+                    Settings.Global.WATCHDOG_TIMEOUT_MILLIS,
                     Settings.Global.Wearable.BATTERY_SAVER_MODE,
                     Settings.Global.Wearable.COMBINED_LOCATION_ENABLED,
                     Settings.Global.Wearable.HAS_PAY_TOKENS,
@@ -659,7 +660,8 @@
                     Settings.Global.Wearable.CLOCKWORK_SYSUI_MAIN_ACTIVITY,
                     Settings.Global.Wearable.CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED,
                     Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_SET_BY_USER,
-                    Settings.Global.Wearable.WET_MODE_ON);
+                    Settings.Global.Wearable.WET_MODE_ON,
+                    Settings.Global.Wearable.COOLDOWN_MODE_ON);
 
     private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
              newHashSet(
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 6f4cd4a..ef5849c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -562,12 +562,14 @@
     <!-- Permissions required for CTS test - TrustTestCases -->
     <uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
     <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
+    <uses-permission android:name="android.permission.TRUST_LISTENER" />
 
     <!-- Permission required for CTS test - CtsGameManagerTestCases -->
     <uses-permission android:name="android.permission.MANAGE_GAME_MODE" />
 
     <!-- Permission required for CTS test - CtsGameServiceTestCases -->
     <uses-permission android:name="android.permission.SET_GAME_SERVICE" />
+    <uses-permission android:name="android.permission.MANAGE_GAME_ACTIVITY" />
 
     <!-- Permission required for CTS test - ClipboardManagerTest -->
     <uses-permission android:name="android.permission.SET_CLIP_SOURCE" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 776a511..c9bd371 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -39,6 +39,7 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
 
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.MODIFY_TOUCH_MODE_STATE" />
     <uses-permission android:name="android.permission.DUMP" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index f7a7603..3051d80 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -19,6 +19,7 @@
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
 import android.animation.ValueAnimator
+import android.app.ActivityManager
 import android.app.Dialog
 import android.graphics.Color
 import android.graphics.Rect
@@ -45,7 +46,8 @@
 class DialogLaunchAnimator @JvmOverloads constructor(
     private val dreamManager: IDreamManager,
     private val launchAnimator: LaunchAnimator = LaunchAnimator(TIMINGS, INTERPOLATORS),
-    private var isForTesting: Boolean = false
+    // TODO(b/217621394): Remove special handling for low-RAM devices after animation sync is fixed
+    private var forceDisableSynchronization: Boolean = ActivityManager.isLowRamDeviceStatic()
 ) {
     private companion object {
         private val TIMINGS = ActivityLaunchAnimator.TIMINGS
@@ -111,7 +113,7 @@
                 dialog = dialog,
                 animateBackgroundBoundsChange,
                 animatedParent,
-                isForTesting
+                forceDisableSynchronization
         )
 
         openedDialogs.add(animatedDialog)
@@ -187,10 +189,9 @@
     private val parentAnimatedDialog: AnimatedDialog? = null,
 
     /**
-     * Whether we are currently running in a test, in which case we need to disable
-     * synchronization.
+     * Whether synchronization should be disabled, which can be useful if we are running in a test.
      */
-    private val isForTesting: Boolean
+    private val forceDisableSynchronization: Boolean
 ) {
     /**
      * The DecorView of this dialog window.
@@ -420,8 +421,9 @@
      * (or inversely, removed from the UI when the touch surface is made visible).
      */
     private fun synchronizeNextDraw(then: () -> Unit) {
-        if (isForTesting || !touchSurface.isAttachedToWindow || touchSurface.viewRootImpl == null ||
-            !decorView.isAttachedToWindow || decorView.viewRootImpl == null) {
+        if (forceDisableSynchronization ||
+                !touchSurface.isAttachedToWindow || touchSurface.viewRootImpl == null ||
+                !decorView.isAttachedToWindow || decorView.viewRootImpl == null) {
             // No need to synchronize if either the touch surface or dialog view is not attached
             // to a window.
             then()
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 29221aa..208825c 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -103,6 +103,20 @@
             n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
             n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 32.0))
     )),
+    RAINBOW(CoreSpec(
+            a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
+            a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
+            a3 = TonalSpec(Hue(HueStrategy.ADD, 60.0), Chroma(ChromaStrategy.EQ, 24.0)),
+            n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 0.0)),
+            n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 0.0))
+    )),
+    FRUIT_SALAD(CoreSpec(
+            a1 = TonalSpec(Hue(HueStrategy.SUBTRACT, 50.0), Chroma(ChromaStrategy.GTE, 48.0)),
+            a2 = TonalSpec(Hue(HueStrategy.SUBTRACT, 50.0), Chroma(ChromaStrategy.EQ, 36.0)),
+            a3 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 36.0)),
+            n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 10.0)),
+            n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
+    )),
 }
 
 class ColorScheme(
diff --git a/services/tests/servicestests/res/xml/test_dream_metadata.xml b/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml
similarity index 74%
copy from services/tests/servicestests/res/xml/test_dream_metadata.xml
copy to packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml
index aa054f1..9891156 100644
--- a/services/tests/servicestests/res/xml/test_dream_metadata.xml
+++ b/packages/SystemUI/res-keyguard/drawable/status_bar_user_chip_bg.xml
@@ -14,6 +14,7 @@
   ~ limitations under the License.
   -->
 
-<dream xmlns:android="http://schemas.android.com/apk/res/android"
-       android:settingsActivity="com.android.server.dreams/.TestDreamSettingsActivity"
-       android:showClockAndComplications="false" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@android:color/system_neutral1_800" />
+    <corners android:radius="@dimen/ongoing_call_chip_corner_radius" />
+</shape>
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 4817d45..c58c001 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -14,126 +14,137 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.systemui.clipboardoverlay.DraggableConstraintLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:theme="@style/FloatingOverlay"
     android:alpha="0"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <ImageView
-        android:id="@+id/actions_container_background"
-        android:visibility="gone"
-        android:layout_height="0dp"
-        android:layout_width="0dp"
-        android:elevation="1dp"
-        android:background="@drawable/action_chip_container_background"
-        android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
-        app:layout_constraintBottom_toBottomOf="@+id/actions_container"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="@+id/actions_container"
-        app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
-    <HorizontalScrollView
-        android:id="@+id/actions_container"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
-        android:paddingEnd="@dimen/overlay_action_container_padding_right"
-        android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
-        android:elevation="1dp"
-        android:scrollbars="none"
-        app:layout_constraintHorizontal_bias="0"
-        app:layout_constraintWidth_percent="1.0"
-        app:layout_constraintWidth_max="wrap"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/preview_border"
-        app:layout_constraintEnd_toEndOf="parent">
-        <LinearLayout
-            android:id="@+id/actions"
+        android:id="@+id/background_protection"
+        android:layout_height="@dimen/overlay_bg_protection_height"
+        android:layout_width="match_parent"
+        android:layout_gravity="bottom"
+        android:src="@drawable/overlay_actions_background_protection"/>
+    <com.android.systemui.clipboardoverlay.DraggableConstraintLayout
+        android:id="@+id/clipboard_ui"
+        android:theme="@style/FloatingOverlay"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <ImageView
+            android:id="@+id/actions_container_background"
+            android:visibility="gone"
+            android:layout_height="0dp"
+            android:layout_width="0dp"
+            android:elevation="1dp"
+            android:background="@drawable/action_chip_container_background"
+            android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
+            app:layout_constraintBottom_toBottomOf="@+id/actions_container"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="@+id/actions_container"
+            app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
+        <HorizontalScrollView
+            android:id="@+id/actions_container"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
+            android:paddingEnd="@dimen/overlay_action_container_padding_right"
+            android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
+            android:elevation="1dp"
+            android:scrollbars="none"
+            app:layout_constraintHorizontal_bias="0"
+            app:layout_constraintWidth_percent="1.0"
+            app:layout_constraintWidth_max="wrap"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toEndOf="@+id/preview_border"
+            app:layout_constraintEnd_toEndOf="parent">
+            <LinearLayout
+                android:id="@+id/actions"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:animateLayoutChanges="true">
+                <include layout="@layout/overlay_action_chip"
+                         android:id="@+id/remote_copy_chip"/>
+                <include layout="@layout/overlay_action_chip"
+                         android:id="@+id/edit_chip"/>
+            </LinearLayout>
+        </HorizontalScrollView>
+        <View
+            android:id="@+id/preview_border"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginStart="@dimen/overlay_offset_x"
+            android:layout_marginBottom="@dimen/overlay_offset_y"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintBottom_toBottomOf="@id/actions_container_background"
+            android:elevation="@dimen/overlay_preview_elevation"
+            app:layout_constraintEnd_toEndOf="@id/clipboard_preview_end"
+            app:layout_constraintTop_toTopOf="@id/clipboard_preview_top"
+            android:background="@drawable/overlay_border"/>
+        <androidx.constraintlayout.widget.Barrier
+            android:id="@+id/clipboard_preview_end"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:animateLayoutChanges="true">
-            <include layout="@layout/overlay_action_chip"
-                     android:id="@+id/remote_copy_chip"/>
-            <include layout="@layout/overlay_action_chip"
-                     android:id="@+id/edit_chip"/>
-        </LinearLayout>
-    </HorizontalScrollView>
-    <View
-        android:id="@+id/preview_border"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_marginStart="@dimen/overlay_offset_x"
-        android:layout_marginBottom="@dimen/overlay_offset_y"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintBottom_toBottomOf="@id/actions_container_background"
-        android:elevation="@dimen/overlay_preview_elevation"
-        app:layout_constraintEnd_toEndOf="@id/clipboard_preview_end"
-        app:layout_constraintTop_toTopOf="@id/clipboard_preview_top"
-        android:background="@drawable/overlay_border"/>
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/clipboard_preview_end"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:barrierMargin="@dimen/overlay_border_width"
-        app:barrierDirection="end"
-        app:constraint_referenced_ids="clipboard_preview"/>
-    <androidx.constraintlayout.widget.Barrier
-        android:id="@+id/clipboard_preview_top"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:barrierDirection="top"
-        app:barrierMargin="@dimen/overlay_border_width_neg"
-        app:constraint_referenced_ids="clipboard_preview"/>
-    <FrameLayout
-        android:id="@+id/clipboard_preview"
-        android:elevation="@dimen/overlay_preview_elevation"
-        android:background="@drawable/overlay_preview_background"
-        android:clipChildren="true"
-        android:clipToOutline="true"
-        android:clipToPadding="true"
-        android:layout_width="@dimen/clipboard_preview_size"
-        android:layout_margin="@dimen/overlay_border_width"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        app:layout_constraintBottom_toBottomOf="@id/preview_border"
-        app:layout_constraintStart_toStartOf="@id/preview_border"
-        app:layout_constraintEnd_toEndOf="@id/preview_border"
-        app:layout_constraintTop_toTopOf="@id/preview_border">
-        <TextView android:id="@+id/text_preview"
-                  android:textFontWeight="500"
-                  android:padding="8dp"
-                  android:gravity="center|start"
-                  android:ellipsize="end"
-                  android:autoSizeTextType="uniform"
-                  android:autoSizeMinTextSize="10sp"
-                  android:autoSizeMaxTextSize="200sp"
-                  android:textColor="?android:attr/textColorPrimary"
-                  android:layout_width="@dimen/clipboard_preview_size"
-                  android:layout_height="@dimen/clipboard_preview_size"/>
-        <ImageView
-            android:id="@+id/image_preview"
-            android:scaleType="fitCenter"
-            android:adjustViewBounds="true"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"/>
-    </FrameLayout>
-    <FrameLayout
-        android:id="@+id/dismiss_button"
-        android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
-        android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
-        android:elevation="@dimen/overlay_dismiss_button_elevation"
-        android:visibility="gone"
-        app:layout_constraintStart_toEndOf="@id/clipboard_preview"
-        app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
-        app:layout_constraintTop_toTopOf="@id/clipboard_preview"
-        app:layout_constraintBottom_toTopOf="@id/clipboard_preview"
-        android:contentDescription="@string/clipboard_dismiss_description">
-        <ImageView
-            android:id="@+id/dismiss_image"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_margin="@dimen/overlay_dismiss_button_margin"
-            android:src="@drawable/overlay_cancel"/>
-    </FrameLayout>
-</com.android.systemui.clipboardoverlay.DraggableConstraintLayout>
+            app:barrierMargin="@dimen/overlay_border_width"
+            app:barrierDirection="end"
+            app:constraint_referenced_ids="clipboard_preview"/>
+        <androidx.constraintlayout.widget.Barrier
+            android:id="@+id/clipboard_preview_top"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            app:barrierDirection="top"
+            app:barrierMargin="@dimen/overlay_border_width_neg"
+            app:constraint_referenced_ids="clipboard_preview"/>
+        <FrameLayout
+            android:id="@+id/clipboard_preview"
+            android:elevation="@dimen/overlay_preview_elevation"
+            android:background="@drawable/overlay_preview_background"
+            android:clipChildren="true"
+            android:clipToOutline="true"
+            android:clipToPadding="true"
+            android:layout_width="@dimen/clipboard_preview_size"
+            android:layout_margin="@dimen/overlay_border_width"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            app:layout_constraintBottom_toBottomOf="@id/preview_border"
+            app:layout_constraintStart_toStartOf="@id/preview_border"
+            app:layout_constraintEnd_toEndOf="@id/preview_border"
+            app:layout_constraintTop_toTopOf="@id/preview_border">
+            <TextView android:id="@+id/text_preview"
+                      android:textFontWeight="500"
+                      android:padding="8dp"
+                      android:gravity="center|start"
+                      android:ellipsize="end"
+                      android:autoSizeTextType="uniform"
+                      android:autoSizeMinTextSize="10sp"
+                      android:autoSizeMaxTextSize="200sp"
+                      android:textColor="?android:attr/textColorPrimary"
+                      android:layout_width="@dimen/clipboard_preview_size"
+                      android:layout_height="@dimen/clipboard_preview_size"/>
+            <ImageView
+                android:id="@+id/image_preview"
+                android:scaleType="fitCenter"
+                android:adjustViewBounds="true"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+        </FrameLayout>
+        <FrameLayout
+            android:id="@+id/dismiss_button"
+            android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
+            android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
+            android:elevation="@dimen/overlay_dismiss_button_elevation"
+            android:visibility="gone"
+            app:layout_constraintStart_toEndOf="@id/clipboard_preview"
+            app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
+            app:layout_constraintTop_toTopOf="@id/clipboard_preview"
+            app:layout_constraintBottom_toTopOf="@id/clipboard_preview"
+            android:contentDescription="@string/clipboard_dismiss_description">
+            <ImageView
+                android:id="@+id/dismiss_image"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_margin="@dimen/overlay_dismiss_button_margin"
+                android:src="@drawable/overlay_cancel"/>
+        </FrameLayout>
+    </com.android.systemui.clipboardoverlay.DraggableConstraintLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index 850b017..e47eed9 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -30,14 +30,39 @@
         android:id="@+id/status_icon_area"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:layout_marginStart="@dimen/system_icons_super_container_margin_start"
         android:paddingTop="@dimen/status_bar_padding_top"
         android:layout_alignParentEnd="true"
         android:gravity="center_vertical|end" >
+        <com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer
+            android:id="@+id/user_switcher_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:orientation="horizontal"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
+            android:paddingStart="8dp"
+            android:paddingEnd="8dp"
+            android:background="@drawable/status_bar_user_chip_bg"
+            android:visibility="visible" >
+            <ImageView android:id="@+id/current_user_avatar"
+                android:layout_width="@dimen/multi_user_avatar_keyguard_size"
+                android:layout_height="@dimen/multi_user_avatar_keyguard_size"
+                android:scaleType="centerInside"
+                android:paddingEnd="4dp" />
+
+            <TextView android:id="@+id/current_user_name"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+                />
+        </com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer>
+
         <FrameLayout android:id="@+id/system_icons_container"
             android:layout_width="0dp"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            android:layout_marginStart="@dimen/system_icons_super_container_margin_start"
             android:layout_marginEnd="@dimen/status_bar_padding_end"
             android:gravity="center_vertical|end">
             <include layout="@layout/system_icons" />
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index 51d1608..978998d 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -29,14 +29,14 @@
     android:theme="@style/MediaPlayer">
 
     <ImageView
+        android:id="@+id/album_art"
         android:layout_width="match_parent"
-        android:layout_height="184dp"
+        android:layout_height="@dimen/qs_media_session_height_expanded"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         android:translationZ="0dp"
-        android:id="@+id/album_art"
         android:scaleType="centerCrop"
         android:adjustViewBounds="true"
         android:clipToOutline="true"
@@ -154,10 +154,7 @@
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_media_padding"
         android:layout_marginTop="0dp"
-        android:layout_marginBottom="0dp"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/media_seamless"
-        app:layout_constraintBottom_toTopOf="@id/actionEnd" />
+        android:layout_marginBottom="0dp" />
 
     <ImageButton
         android:id="@+id/actionPrev"
@@ -168,11 +165,8 @@
         android:layout_marginEnd="0dp"
         android:layout_marginBottom="0dp"
         android:layout_marginTop="0dp"
-        app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+        app:layout_constraintHorizontal_bias="1"
+        app:layout_constraintHorizontal_chainStyle="packed" />
 
     <!-- Seek Bar -->
     <!-- As per Material Design on Bidirectionality, this is forced to LTR in code -->
@@ -188,11 +182,7 @@
         android:layout_marginBottom="0dp"
         android:layout_marginTop="0dp"
         android:layout_marginStart="0dp"
-        android:layout_marginEnd="0dp"
-        app:layout_constraintStart_toEndOf="@id/actionPrev"
-        app:layout_constraintEnd_toStartOf="@id/actionNext"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+        android:layout_marginEnd="0dp" />
 
     <ImageButton
         android:id="@+id/actionNext"
@@ -202,11 +192,7 @@
         android:layout_marginStart="0dp"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="0dp"
-        android:layout_marginTop="0dp"
-        app:layout_constraintStart_toEndOf="@id/media_progress_bar"
-        app:layout_constraintEnd_toStartOf="@id/actionStart"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+        android:layout_marginTop="0dp" />
 
     <ImageButton
         android:id="@+id/actionStart"
@@ -216,11 +202,7 @@
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="0dp"
-        android:layout_marginTop="0dp"
-        app:layout_constraintStart_toEndOf="@id/actionNext"
-        app:layout_constraintEnd_toStartOf="@id/actionEnd"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+        android:layout_marginTop="0dp" />
 
     <ImageButton
         android:id="@+id/actionEnd"
@@ -231,11 +213,7 @@
         android:layout_marginEnd="4dp"
         android:layout_marginBottom="0dp"
         android:layout_marginTop="0dp"
-        app:layout_constraintHorizontal_chainStyle="packed"
-        app:layout_constraintStart_toEndOf="@id/actionStart"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+        app:layout_constraintHorizontal_chainStyle="packed" />
 
     <!-- Long press menu -->
     <TextView
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 536b042..02c58e4 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -26,9 +26,9 @@
     android:layout_marginEnd="0dp"
     android:layout_gravity="center_vertical | start">
 
-    <TextView
+    <com.android.systemui.util.SafeMarqueeTextView
         android:id="@+id/tile_label"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="start"
         android:textDirection="locale"
@@ -37,9 +37,9 @@
         android:singleLine="true"
         android:textAppearance="@style/TextAppearance.QS.TileLabel"/>
 
-    <TextView
+    <com.android.systemui.util.SafeMarqueeTextView
         android:id="@+id/app_label"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="start"
         android:textDirection="locale"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 8b244c7..af98019 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -119,6 +119,32 @@
             android:gravity="center_vertical|end"
             >
 
+            <com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer
+                android:id="@+id/user_switcher_container"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:orientation="horizontal"
+                android:paddingTop="4dp"
+                android:paddingBottom="4dp"
+                android:paddingStart="8dp"
+                android:paddingEnd="8dp"
+                android:layout_marginEnd="16dp"
+                android:background="@drawable/status_bar_user_chip_bg"
+                android:visibility="visible" >
+                <ImageView android:id="@+id/current_user_avatar"
+                    android:layout_width="@dimen/multi_user_avatar_keyguard_size"
+                    android:layout_height="@dimen/multi_user_avatar_keyguard_size"
+                    android:scaleType="centerInside"
+                    android:paddingEnd="4dp" />
+
+                <TextView android:id="@+id/current_user_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+                    />
+            </com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer>
+
             <include layout="@layout/system_icons" />
         </com.android.keyguard.AlphaOptimizedLinearLayout>
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml
index 6d5c7d4..4f4bae4 100644
--- a/packages/SystemUI/res/layout/system_icons.xml
+++ b/packages/SystemUI/res/layout/system_icons.xml
@@ -17,7 +17,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/system_icons"
-    android:layout_width="match_parent"
+    android:layout_width="wrap_content"
     android:layout_height="match_parent"
     android:gravity="center_vertical">
 
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 1b8453a..abc69b0 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -23,6 +23,9 @@
     <!-- The maximum number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">4</integer>
 
+    <!-- Use collapsed layout for media player in landscape QQS -->
+    <bool name="config_quickSettingsMediaLandscapeCollapsed">false</bool>
+
     <!-- Nav bar button default ordering/layout -->
     <string name="config_navBarLayout" translatable="false">left;back,home,recent;right</string>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 079f5d0..47822b7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -102,6 +102,9 @@
         <item>one_handed_mode_enabled:onehanded</item>
     </string-array>
 
+    <!-- Use collapsed layout for media player in landscape QQS -->
+    <bool name="config_quickSettingsMediaLandscapeCollapsed">true</bool>
+
     <!-- Show indicator for Wifi on but not connected. -->
     <bool name="config_showWifiIndicatorWhenEnabled">false</bool>
 
@@ -683,7 +686,7 @@
     <integer name="config_connectionMinDuration">1000</integer>
 
     <!-- Flag to activate notification to contents feature -->
-    <bool name="config_notificationToContents">false</bool>
+    <bool name="config_notificationToContents">true</bool>
 
     <!-- Respect drawable/rounded_secondary.xml intrinsic size for multiple radius corner path
          customization for secondary display-->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 349a2a8..7eb25db 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -990,6 +990,8 @@
     <!-- Sizes for alternate session-based layout -->
     <dimen name="qs_media_session_enabled_seekbar_vertical_padding">15dp</dimen>
     <dimen name="qs_media_session_disabled_seekbar_vertical_padding">16dp</dimen>
+    <dimen name="qs_media_session_height_expanded">184dp</dimen>
+    <dimen name="qs_media_session_height_collapsed">128dp</dimen>
 
     <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
     <dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 2a70645..49dd574 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -32,4 +32,8 @@
 
     <bool name="flag_smartspace">false</bool>
 
+    <!--  Whether the user switcher chip shows in the status bar. When true, the multi user
+      avatar will no longer show on the lockscreen -->
+    <bool name="flag_user_switcher_chip">false</bool>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4dca0b0..e5cabb0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2379,11 +2379,15 @@
     <string name="fgs_manager_dialog_title">Active apps</string>
     <!-- Label of the button to stop an app from running [CHAR LIMIT=12]-->
     <string name="fgs_manager_app_item_stop_button_label">Stop</string>
+    <!-- Label of the button to stop an app from running but the app is already stopped and the button is disabled [CHAR LIMIT=12]-->
+    <string name="fgs_manager_app_item_stop_button_stopped_label">Stopped</string>
 
     <!-- Label for button to copy edited text back to the clipboard [CHAR LIMIT=20] -->
     <string name="clipboard_edit_text_copy">Copy</string>
     <!-- Text informing user that content has been copied to the system clipboard [CHAR LIMIT=NONE] -->
     <string name="clipboard_overlay_text_copied">Copied</string>
+    <!-- Text informing user where text being edited was copied from [CHAR LIMIT=NONE] -->
+    <string name="clipboard_edit_source">From <xliff:g id="appName" example="Gmail">%1$s</xliff:g></string>
     <!-- Label for button to dismiss clipboard overlay [CHAR LIMIT=NONE] -->
     <string name="clipboard_dismiss_description">Dismiss copy UI</string>
 </resources>
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
new file mode 100644
index 0000000..c6e18a6
--- /dev/null
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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
+  -->
+<ConstraintSet
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <Constraint
+        android:id="@+id/album_art"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/qs_media_session_height_collapsed"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent" />
+
+    <Constraint
+        android:id="@+id/actionPlayPause"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginEnd="@dimen/qs_media_padding"
+        app:layout_constraintStart_toEndOf="@id/actionEnd"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless"
+        app:layout_constraintBottom_toBottomOf="parent" />
+
+    <Constraint
+        android:id="@+id/actionPrev"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        app:layout_constraintHorizontal_bias="1"
+        app:layout_constraintHorizontal_chainStyle="packed"
+        app:layout_constraintStart_toEndOf="@id/header_artist"
+        app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+    <Constraint
+        android:id="@+id/media_progress_bar"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        app:layout_constraintStart_toEndOf="@id/actionPrev"
+        app:layout_constraintEnd_toStartOf="@id/actionNext"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+    <Constraint
+        android:id="@+id/actionNext"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        app:layout_constraintStart_toEndOf="@id/media_progress_bar"
+        app:layout_constraintEnd_toStartOf="@id/actionStart"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+    <Constraint
+        android:id="@+id/actionStart"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:visibility="gone"
+        app:layout_constraintStart_toEndOf="@id/actionNext"
+        app:layout_constraintEnd_toStartOf="@id/actionEnd"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+    <Constraint
+        android:id="@+id/actionEnd"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:visibility="gone"
+        app:layout_constraintStart_toEndOf="@id/actionStart"
+        app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+</ConstraintSet>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
new file mode 100644
index 0000000..18ec7aa
--- /dev/null
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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
+  -->
+<ConstraintSet
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <Constraint
+        android:id="@+id/album_art"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/qs_media_session_height_expanded"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent" />
+
+    <Constraint
+        android:id="@+id/actionPlayPause"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginEnd="@dimen/qs_media_padding"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless"
+        app:layout_constraintBottom_toTopOf="@id/actionEnd" />
+
+    <Constraint
+        android:id="@+id/actionPrev"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+    <Constraint
+        android:id="@+id/media_progress_bar"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        app:layout_constraintStart_toEndOf="@id/actionPrev"
+        app:layout_constraintEnd_toStartOf="@id/actionNext"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+    <Constraint
+        android:id="@+id/actionNext"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        app:layout_constraintStart_toEndOf="@id/media_progress_bar"
+        app:layout_constraintEnd_toStartOf="@id/actionStart"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+    <Constraint
+        android:id="@+id/actionStart"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        app:layout_constraintStart_toEndOf="@id/actionNext"
+        app:layout_constraintEnd_toStartOf="@id/actionEnd"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+    <Constraint
+        android:id="@+id/actionEnd"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        app:layout_constraintStart_toEndOf="@id/actionStart"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+
+</ConstraintSet>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 8d98a75..56326e3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -18,6 +18,7 @@
 
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN;
 
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -110,11 +111,16 @@
                 hints &= ~NAVIGATION_HINT_BACK_ALT;
                 break;
         }
-        if (showImeSwitcher) {
+        if (imeShown) {
             hints |= NAVIGATION_HINT_IME_SHOWN;
         } else {
             hints &= ~NAVIGATION_HINT_IME_SHOWN;
         }
+        if (showImeSwitcher) {
+            hints |= NAVIGATION_HINT_IME_SWITCHER_SHOWN;
+        } else {
+            hints &= ~NAVIGATION_HINT_IME_SWITCHER_SHOWN;
+        }
 
         return hints;
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index eebc791..08b4d3f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -59,6 +59,7 @@
     public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation";
     // See IRecentTasks.aidl
     public static final String KEY_EXTRA_RECENT_TASKS = "recent_tasks";
+    public static final String KEY_EXTRA_SHELL_BACK_ANIMATION = "extra_shell_back_animation";
 
     public static final String NAV_BAR_MODE_3BUTTON_OVERLAY =
             WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
index fc14b6a..8fc8600 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
@@ -20,7 +20,11 @@
 import com.android.systemui.R;
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherControllerImpl;
 
+import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
 
@@ -39,4 +43,17 @@
     static BatteryMeterView getBatteryMeterView(KeyguardStatusBarView view) {
         return view.findViewById(R.id.battery);
     }
+
+    /** */
+    @Provides
+    @KeyguardStatusBarViewScope
+    static StatusBarUserSwitcherContainer getUserSwitcherContainer(KeyguardStatusBarView view) {
+        return view.findViewById(R.id.user_switcher_container);
+    }
+
+    /** */
+    @Binds
+    @KeyguardStatusBarViewScope
+    abstract StatusBarUserSwitcherController bindStatusBarUserSwitcherController(
+            StatusBarUserSwitcherControllerImpl controller);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 4a0c30c..3d0c08b 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -39,6 +39,8 @@
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.systemui.animation.Interpolators;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -82,6 +84,7 @@
     private final int mSwipeDirection;
     private final VelocityTracker mVelocityTracker;
     private final FalsingManager mFalsingManager;
+    private final FeatureFlags mFeatureFlags;
 
     private float mInitialTouchPos;
     private float mPerpendicularInitialTouchPos;
@@ -128,7 +131,8 @@
 
     public SwipeHelper(
             int swipeDirection, Callback callback, Resources resources,
-            ViewConfiguration viewConfiguration, FalsingManager falsingManager) {
+            ViewConfiguration viewConfiguration, FalsingManager falsingManager,
+            FeatureFlags featureFlags) {
         mCallback = callback;
         mHandler = new Handler();
         mSwipeDirection = swipeDirection;
@@ -146,6 +150,7 @@
         mFadeDependingOnAmountSwiped = resources.getBoolean(
                 R.bool.config_fadeDependingOnAmountSwiped);
         mFalsingManager = falsingManager;
+        mFeatureFlags = featureFlags;
         mFlingAnimationUtils = new FlingAnimationUtils(resources.getDisplayMetrics(),
                 getMaxEscapeAnimDuration() / 1000f);
     }
@@ -795,7 +800,7 @@
     }
 
     private boolean isAvailableToDragAndDrop(View v) {
-        if (v.getResources().getBoolean(R.bool.config_notificationToContents)) {
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_DRAG_TO_CONTENTS)) {
             if (v instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow enr = (ExpandableNotificationRow) v;
                 boolean canBubble = enr.getEntry().canBubble();
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index 72b40d4..54664f2 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -48,7 +48,7 @@
     @Override
     public void start() {
         if (DeviceConfig.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, false)) {
+                DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, true)) {
             mClipboardManager = requireNonNull(mContext.getSystemService(ClipboardManager.class));
             mClipboardManager.addPrimaryClipChangedListener(this);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 8b549b4..f6d6464 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -103,6 +103,7 @@
     private final AccessibilityManager mAccessibilityManager;
     private final TextClassifier mTextClassifier;
 
+    private final FrameLayout mContainer;
     private final DraggableConstraintLayout mView;
     private final ImageView mImagePreview;
     private final TextView mTextPreview;
@@ -147,8 +148,9 @@
         mWindow = FloatingWindowUtil.getFloatingWindow(mContext);
         mWindow.setWindowManager(mWindowManager, null, null);
 
-        mView = (DraggableConstraintLayout)
+        mContainer = (FrameLayout)
                 LayoutInflater.from(mContext).inflate(R.layout.clipboard_overlay, null);
+        mView = requireNonNull(mContainer.findViewById(R.id.clipboard_ui));
         mActionContainerBackground =
                 requireNonNull(mView.findViewById(R.id.actions_container_background));
         mActionContainer = requireNonNull(mView.findViewById(R.id.actions));
@@ -180,7 +182,7 @@
 
         attachWindow();
         withWindowAttached(() -> {
-            mWindow.setContentView(mView);
+            mWindow.setContentView(mContainer);
             updateInsets(mWindowManager.getCurrentWindowMetrics().getWindowInsets());
             mView.requestLayout();
             mView.post(this::animateIn);
@@ -371,7 +373,7 @@
     private ValueAnimator getEnterAnimation() {
         ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
 
-        mView.setAlpha(0);
+        mContainer.setAlpha(0);
         mDismissButton.setVisibility(View.GONE);
         final View previewBorder = requireNonNull(mView.findViewById(R.id.preview_border));
         final View actionBackground = requireNonNull(
@@ -383,7 +385,7 @@
         }
 
         anim.addUpdateListener(animation -> {
-            mView.setAlpha(animation.getAnimatedFraction());
+            mContainer.setAlpha(animation.getAnimatedFraction());
             float scale = 0.6f + 0.4f * animation.getAnimatedFraction();
             mView.setPivotY(mView.getHeight() - previewBorder.getHeight() / 2f);
             mView.setPivotX(actionBackground.getWidth() / 2f);
@@ -394,7 +396,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 super.onAnimationEnd(animation);
-                mView.setAlpha(1);
+                mContainer.setAlpha(1);
                 mTimeoutHandler.resetTimeout();
             }
         });
@@ -439,7 +441,7 @@
 
     private void reset() {
         mView.setTranslationX(0);
-        mView.setAlpha(0);
+        mContainer.setAlpha(0);
         resetActionChips();
         mTimeoutHandler.cancelTimeout();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
index be10c35..a57a135 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
@@ -22,9 +22,12 @@
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 
@@ -32,8 +35,11 @@
  * Lightweight activity for editing text clipboard contents
  */
 public class EditTextActivity extends Activity {
+    private static final String TAG = "EditTextActivity";
+
     private EditText mEditText;
     private ClipboardManager mClipboardManager;
+    private TextView mAttribution;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -42,6 +48,7 @@
         findViewById(R.id.copy_button).setOnClickListener((v) -> saveToClipboard());
         findViewById(R.id.share).setOnClickListener((v) -> share());
         mEditText = findViewById(R.id.edit_text);
+        mAttribution = findViewById(R.id.attribution);
         mClipboardManager = requireNonNull(getSystemService(ClipboardManager.class));
     }
 
@@ -53,7 +60,15 @@
             finish();
             return;
         }
-        // TODO: put clip attribution in R.id.attribution TextView
+        PackageManager pm = getApplicationContext().getPackageManager();
+        try {
+            CharSequence label = pm.getApplicationLabel(
+                    pm.getApplicationInfo(mClipboardManager.getPrimaryClipSource(),
+                            PackageManager.ApplicationInfoFlags.of(0)));
+            mAttribution.setText(getResources().getString(R.string.clipboard_edit_source, label));
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "Package not found: " + mClipboardManager.getPrimaryClipSource(), e);
+        }
         mEditText.setText(clip.getItemAt(0).getText());
         mEditText.requestFocus();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 5a52fd0..59c291c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -437,7 +437,7 @@
      * number of columns. This helps prevent text truncation on these devices.
      */
     private fun findMaxColumns(): Int {
-        val res = context.resources
+        val res = activityContext.resources
         var maxColumns = res.getInteger(R.integer.controls_max_columns)
         val maxColumnsAdjustWidth =
             res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp)
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 20cd5b9..68b74bd 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -41,6 +41,7 @@
 import com.android.systemui.doze.DozeMachine.State;
 import com.android.systemui.doze.dagger.DozeScope;
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.Assert;
@@ -96,6 +97,7 @@
     private final AuthController mAuthController;
     private final DelayableExecutor mMainExecutor;
     private final KeyguardStateController mKeyguardStateController;
+    private final BatteryController mBatteryController;
     private final UiEventLogger mUiEventLogger;
     private final DevicePostureController mDevicePostureController;
 
@@ -187,7 +189,8 @@
             @Main DelayableExecutor mainExecutor,
             UiEventLogger uiEventLogger,
             KeyguardStateController keyguardStateController,
-            DevicePostureController devicePostureController) {
+            DevicePostureController devicePostureController,
+            BatteryController batteryController) {
         mContext = context;
         mDozeHost = dozeHost;
         mConfig = config;
@@ -210,6 +213,7 @@
         mMainExecutor = mainExecutor;
         mUiEventLogger = uiEventLogger;
         mKeyguardStateController = keyguardStateController;
+        mBatteryController = batteryController;
     }
     private final DevicePostureController.Callback mDevicePostureCallback =
             posture -> {
@@ -320,7 +324,12 @@
                     gentleWakeUp(pulseReason);
                 } else if (isPickup) {
                     if (shouldDropPickupEvent())  {
-                        mDozeLog.traceSensorEventDropped(pulseReason, "keyguard occluded");
+                        mDozeLog.traceSensorEventDropped(
+                                pulseReason,
+                                "keyguardOccluded="
+                                        + mKeyguardStateController.isOccluded()
+                                        + " pluggedInWireless="
+                                        + mBatteryController.isPluggedInWireless());
                         return;
                     }
                     gentleWakeUp(pulseReason);
@@ -351,7 +360,7 @@
     }
 
     private boolean shouldDropPickupEvent() {
-        return mKeyguardStateController.isOccluded();
+        return mKeyguardStateController.isOccluded() || mBatteryController.isPluggedInWireless();
     }
 
     private void gentleWakeUp(int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt
deleted file mode 100644
index 42f3512..0000000
--- a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.systemui.fgsmanager
-
-import android.content.Context
-import android.os.Bundle
-import android.text.format.DateUtils
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Button
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.annotation.GuardedBy
-import androidx.recyclerview.widget.DiffUtil
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import com.android.systemui.R
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.fgsmanager.FgsManagerDialogController.RunningApp
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.util.time.SystemClock
-import java.util.concurrent.Executor
-
-/**
- * Dialog which shows a list of running foreground services and offers controls to them
- */
-class FgsManagerDialog(
-    context: Context,
-    private val executor: Executor,
-    @Background private val backgroundExecutor: Executor,
-    private val systemClock: SystemClock,
-    private val fgsManagerDialogController: FgsManagerDialogController
-) : SystemUIDialog(context, R.style.Theme_SystemUI_Dialog) {
-
-    private val appListRecyclerView: RecyclerView = RecyclerView(this.context)
-    private val adapter: AppListAdapter = AppListAdapter()
-
-    init {
-        setTitle(R.string.fgs_manager_dialog_title)
-        setView(appListRecyclerView)
-    }
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        appListRecyclerView.layoutManager = LinearLayoutManager(context)
-        fgsManagerDialogController.registerDialogForChanges(
-                object : FgsManagerDialogController.FgsManagerDialogCallback {
-                    override fun onRunningAppsChanged(apps: List<RunningApp>) {
-                        executor.execute {
-                            adapter.setData(apps)
-                        }
-                    }
-                }
-        )
-        appListRecyclerView.adapter = adapter
-        backgroundExecutor.execute { adapter.setData(fgsManagerDialogController.runningAppList) }
-    }
-
-    private inner class AppListAdapter : RecyclerView.Adapter<AppItemViewHolder>() {
-        private val lock = Any()
-
-        @GuardedBy("lock")
-        private val data: MutableList<RunningApp> = ArrayList()
-        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppItemViewHolder {
-            return AppItemViewHolder(LayoutInflater.from(context)
-                            .inflate(R.layout.fgs_manager_app_item, parent, false))
-        }
-
-        override fun onBindViewHolder(holder: AppItemViewHolder, position: Int) {
-            var runningApp: RunningApp
-            synchronized(lock) {
-                runningApp = data[position]
-            }
-            with(holder) {
-                iconView.setImageDrawable(runningApp.mIcon)
-                appLabelView.text = runningApp.mAppLabel
-                durationView.text = DateUtils.formatDuration(
-                        Math.max(systemClock.elapsedRealtime() - runningApp.mTimeStarted, 60000),
-                        DateUtils.LENGTH_MEDIUM)
-                stopButton.setOnClickListener {
-                    fgsManagerDialogController
-                            .stopAllFgs(runningApp.mUserId, runningApp.mPackageName)
-                }
-            }
-        }
-
-        override fun getItemCount(): Int {
-            synchronized(lock) { return data.size }
-        }
-
-        fun setData(newData: List<RunningApp>) {
-            var oldData: List<RunningApp>
-            synchronized(lock) {
-                oldData = ArrayList(data)
-                data.clear()
-                data.addAll(newData)
-            }
-
-            DiffUtil.calculateDiff(object : DiffUtil.Callback() {
-                override fun getOldListSize(): Int {
-                    return oldData.size
-                }
-
-                override fun getNewListSize(): Int {
-                    return newData.size
-                }
-
-                override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int):
-                        Boolean {
-                    return oldData[oldItemPosition] == newData[newItemPosition]
-                }
-
-                override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int):
-                        Boolean {
-                    return true // TODO, look into updating the time subtext
-                }
-            }).dispatchUpdatesTo(this)
-        }
-    }
-
-    private class AppItemViewHolder(parent: View) : RecyclerView.ViewHolder(parent) {
-        val appLabelView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_label)
-        val durationView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_duration)
-        val iconView: ImageView = parent.requireViewById(R.id.fgs_manager_app_item_icon)
-        val stopButton: Button = parent.requireViewById(R.id.fgs_manager_app_item_stop_button)
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt
deleted file mode 100644
index 159ed39..0000000
--- a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.systemui.fgsmanager
-
-import android.content.pm.PackageManager
-import android.content.pm.PackageManager.NameNotFoundException
-import android.graphics.drawable.Drawable
-import android.os.Handler
-import android.os.UserHandle
-import android.util.ArrayMap
-import android.util.Log
-import androidx.annotation.GuardedBy
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.statusbar.policy.RunningFgsController
-import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime
-import javax.inject.Inject
-
-/**
- * Controls events relevant to FgsManagerDialog
- */
-class FgsManagerDialogController @Inject constructor(
-    private val packageManager: PackageManager,
-    @Background private val backgroundHandler: Handler,
-    private val runningFgsController: RunningFgsController
-) : RunningFgsController.Callback {
-    private val lock = Any()
-    private val clearCacheToken = Any()
-
-    @GuardedBy("lock")
-    private var runningApps: Map<UserPackageTime, RunningApp>? = null
-    @GuardedBy("lock")
-    private var listener: FgsManagerDialogCallback? = null
-
-    interface FgsManagerDialogCallback {
-        fun onRunningAppsChanged(apps: List<RunningApp>)
-    }
-
-    data class RunningApp(
-        val mUserId: Int,
-        val mPackageName: String,
-        val mAppLabel: CharSequence,
-        val mIcon: Drawable,
-        val mTimeStarted: Long
-    )
-
-    val runningAppList: List<RunningApp>
-        get() {
-            synchronized(lock) {
-                if (runningApps == null) {
-                    onFgsPackagesChangedLocked(runningFgsController.getPackagesWithFgs())
-                }
-                return convertToRunningAppList(runningApps!!)
-            }
-        }
-
-    fun registerDialogForChanges(callback: FgsManagerDialogCallback) {
-        synchronized(lock) {
-            runningFgsController.addCallback(this)
-            listener = callback
-            backgroundHandler.removeCallbacksAndMessages(clearCacheToken)
-        }
-    }
-
-    fun onFinishDialog() {
-        synchronized(lock) {
-            listener = null
-            // Keep data such as icons cached for some time since loading can be slow
-            backgroundHandler.postDelayed(
-                    {
-                        synchronized(lock) {
-                            runningFgsController.removeCallback(this)
-                            runningApps = null
-                        }
-                    }, clearCacheToken, RUNNING_APP_CACHE_TIMEOUT_MILLIS)
-        }
-    }
-
-    private fun onRunningAppsChanged(apps: ArrayMap<UserPackageTime, RunningApp>) {
-        listener?.let {
-            backgroundHandler.post { it.onRunningAppsChanged(convertToRunningAppList(apps)) }
-        }
-    }
-
-    override fun onFgsPackagesChanged(packages: List<UserPackageTime>) {
-        backgroundHandler.post {
-            synchronized(lock) { onFgsPackagesChangedLocked(packages) }
-        }
-    }
-
-    /**
-     * Run on background thread
-     */
-    private fun onFgsPackagesChangedLocked(packages: List<UserPackageTime>) {
-        val newRunningApps = ArrayMap<UserPackageTime, RunningApp>()
-        for (packageWithFgs in packages) {
-            val ra = runningApps?.get(packageWithFgs)
-            if (ra == null) {
-                val userId = packageWithFgs.userId
-                val packageName = packageWithFgs.packageName
-                try {
-                    val ai = packageManager.getApplicationInfo(packageName, 0)
-                    var icon = packageManager.getApplicationIcon(ai)
-                    icon = packageManager.getUserBadgedIcon(icon,
-                            UserHandle.of(userId))
-                    val label = packageManager.getApplicationLabel(ai)
-                    newRunningApps[packageWithFgs] = RunningApp(userId, packageName,
-                            label, icon, packageWithFgs.startTimeMillis)
-                } catch (e: NameNotFoundException) {
-                    Log.e(LOG_TAG,
-                            "Application info not found: $packageName", e)
-                }
-            } else {
-                newRunningApps[packageWithFgs] = ra
-            }
-        }
-        runningApps = newRunningApps
-        onRunningAppsChanged(newRunningApps)
-    }
-
-    fun stopAllFgs(userId: Int, packageName: String) {
-        runningFgsController.stopFgs(userId, packageName)
-    }
-
-    companion object {
-        private val LOG_TAG = FgsManagerDialogController::class.java.simpleName
-        private const val RUNNING_APP_CACHE_TIMEOUT_MILLIS: Long = 20_000
-
-        private fun convertToRunningAppList(apps: Map<UserPackageTime, RunningApp>):
-                List<RunningApp> {
-            val result = mutableListOf<RunningApp>()
-            result.addAll(apps.values)
-            result.sortWith { a: RunningApp, b: RunningApp ->
-                b.mTimeStarted.compareTo(a.mTimeStarted)
-            }
-            return result
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt
deleted file mode 100644
index 2874929..0000000
--- a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.systemui.fgsmanager
-
-import android.content.Context
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.animation.DialogLaunchAnimator
-import android.content.DialogInterface
-import android.view.View
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.util.time.SystemClock
-import java.util.concurrent.Executor
-import javax.inject.Inject
-
-/**
- * Factory to create [FgsManagerDialog] instances
- */
-@SysUISingleton
-class FgsManagerDialogFactory
-@Inject constructor(
-    private val context: Context,
-    @Main private val executor: Executor,
-    @Background private val backgroundExecutor: Executor,
-    private val systemClock: SystemClock,
-    private val dialogLaunchAnimator: DialogLaunchAnimator,
-    private val fgsManagerDialogController: FgsManagerDialogController
-) {
-
-    val lock = Any()
-
-    companion object {
-        private var fgsManagerDialog: FgsManagerDialog? = null
-    }
-
-    /**
-     * Creates the dialog if it doesn't exist
-     */
-    fun create(viewLaunchedFrom: View?) {
-        if (fgsManagerDialog == null) {
-            fgsManagerDialog = FgsManagerDialog(context, executor, backgroundExecutor,
-                    systemClock, fgsManagerDialogController)
-            fgsManagerDialog!!.setOnDismissListener { i: DialogInterface? ->
-                fgsManagerDialogController.onFinishDialog()
-                fgsManagerDialog = null
-            }
-            dialogLaunchAnimator.showFromView(fgsManagerDialog!!, viewLaunchedFrom!!)
-        }
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 357a68f..12c6e00 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -46,9 +46,6 @@
     public static final BooleanFlag NOTIFICATION_PIPELINE_DEVELOPER_LOGGING =
             new BooleanFlag(103, false);
 
-    public static final ResourceBooleanFlag NOTIFICATION_SHADE_DRAG =
-            new ResourceBooleanFlag(104, R.bool.config_enableNotificationShadeDrag);
-
     public static final BooleanFlag NSSL_DEBUG_LINES =
             new BooleanFlag(105, false);
 
@@ -58,6 +55,9 @@
     public static final BooleanFlag NEW_PIPELINE_CRASH_ON_CALL_TO_OLD_PIPELINE =
             new BooleanFlag(107, false);
 
+    public static final ResourceBooleanFlag NOTIFICATION_DRAG_TO_CONTENTS =
+            new ResourceBooleanFlag(108, R.bool.config_notificationToContents);
+
     /***************************************/
     // 200 - keyguard/lockscreen
 
@@ -114,8 +114,8 @@
     public static final BooleanFlag COMBINED_STATUS_BAR_SIGNAL_ICONS =
             new BooleanFlag(601, false);
 
-    public static final BooleanFlag STATUS_BAR_USER_SWITCHER =
-            new BooleanFlag(602, false);
+    public static final ResourceBooleanFlag STATUS_BAR_USER_SWITCHER =
+            new ResourceBooleanFlag(602, R.bool.flag_user_switcher_chip);
 
     /***************************************/
     // 700 - dialer/calls
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 30429fb..2a73797 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -49,7 +49,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIAppComponentFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -139,6 +138,8 @@
     public StatusBarStateController mStatusBarStateController;
     @Inject
     public KeyguardBypassController mKeyguardBypassController;
+    @Inject
+    public KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private CharSequence mMediaTitle;
     private CharSequence mMediaArtist;
     protected boolean mDozing;
@@ -333,7 +334,7 @@
             mAlarmManager.cancel(mUpdateNextAlarm);
             if (mRegistered) {
                 mRegistered = false;
-                getKeyguardUpdateMonitor().removeCallback(mKeyguardUpdateMonitorCallback);
+                mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
                 getContext().unregisterReceiver(mIntentReceiver);
             }
             KeyguardSliceProvider.sInstance = null;
@@ -389,7 +390,7 @@
             filter.addAction(Intent.ACTION_LOCALE_CHANGED);
             getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
                     null /* scheduler */);
-            getKeyguardUpdateMonitor().registerCallback(mKeyguardUpdateMonitorCallback);
+            mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
             mRegistered = true;
         }
     }
@@ -441,10 +442,6 @@
         updateNextAlarm();
     }
 
-    private KeyguardUpdateMonitor getKeyguardUpdateMonitor() {
-        return Dependency.get(KeyguardUpdateMonitor.class);
-    }
-
     /**
      * Called whenever new media metadata is available.
      * @param metadata New metadata.
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index 48f4826..c3f4ce9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -45,7 +45,8 @@
     private val statusBarStateController: SysuiStatusBarStateController,
     private val notifLockscreenUserManager: NotificationLockscreenUserManager,
     private val context: Context,
-    configurationController: ConfigurationController
+    configurationController: ConfigurationController,
+    private val mediaFlags: MediaFlags
 ) {
 
     init {
@@ -61,7 +62,11 @@
         })
 
         // First let's set the desired state that we want for this host
-        mediaHost.expansion = MediaHostState.COLLAPSED
+        mediaHost.expansion = if (mediaFlags.useMediaSessionLayout()) {
+            MediaHostState.EXPANDED
+        } else {
+            MediaHostState.COLLAPSED
+        }
         mediaHost.showsOnlyActiveMedia = true
         mediaHost.falsingProtectionNeeded = true
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 0223c60..240ca36 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -657,7 +657,10 @@
                 }
                 val runnable = if (action.actionIntent != null) {
                     Runnable {
-                        if (action.isAuthenticationRequired()) {
+                        if (action.actionIntent.isActivity) {
+                            activityStarter.startPendingIntentDismissingKeyguard(
+                                action.actionIntent)
+                        } else if (action.isAuthenticationRequired()) {
                             activityStarter.dismissKeyguardThenExecute({
                                 var result = sendPendingIntent(action.actionIntent)
                                 result
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 791a312..591aad1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -471,14 +471,16 @@
 
     private fun updateMediaViewControllerType(type: TYPE) {
         this.type = type
+
+        // These XML resources contain ConstraintSets that will apply to this player type's layout
         when (type) {
             TYPE.PLAYER -> {
                 collapsedLayout.load(context, R.xml.media_collapsed)
                 expandedLayout.load(context, R.xml.media_expanded)
             }
             TYPE.PLAYER_SESSION -> {
-                collapsedLayout.clone(context, R.layout.media_session_view)
-                expandedLayout.clone(context, R.layout.media_session_view)
+                collapsedLayout.load(context, R.xml.media_session_collapsed)
+                expandedLayout.load(context, R.xml.media_session_expanded)
             }
             TYPE.RECOMMENDATION -> {
                 collapsedLayout.load(context, R.xml.media_recommendation_collapsed)
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 8684509..f8b34f9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -21,6 +21,7 @@
 import android.view.WindowManager;
 
 import com.android.systemui.dagger.SysUISingleton;
+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;
@@ -35,6 +36,7 @@
 import com.android.systemui.statusbar.commandline.CommandRegistry;
 
 import java.util.Optional;
+import java.util.concurrent.Executor;
 
 import javax.inject.Named;
 
@@ -99,13 +101,13 @@
     @SysUISingleton
     static Optional<MediaTttChipControllerSender> providesMediaTttChipControllerSender(
             MediaTttFlags mediaTttFlags,
+            CommandQueue commandQueue,
             Context context,
-            WindowManager windowManager,
-            CommandQueue commandQueue) {
+            WindowManager windowManager) {
         if (!mediaTttFlags.isMediaTttEnabled()) {
             return Optional.empty();
         }
-        return Optional.of(new MediaTttChipControllerSender(context, windowManager, commandQueue));
+        return Optional.of(new MediaTttChipControllerSender(commandQueue, context, windowManager));
     }
 
     /** */
@@ -113,12 +115,14 @@
     @SysUISingleton
     static Optional<MediaTttChipControllerReceiver> providesMediaTttChipControllerReceiver(
             MediaTttFlags mediaTttFlags,
+            CommandQueue commandQueue,
             Context context,
             WindowManager windowManager) {
         if (!mediaTttFlags.isMediaTttEnabled()) {
             return Optional.empty();
         }
-        return Optional.of(new MediaTttChipControllerReceiver(context, windowManager));
+        return Optional.of(
+                new MediaTttChipControllerReceiver(commandQueue, context, windowManager));
     }
 
     /** */
@@ -128,15 +132,12 @@
             MediaTttFlags mediaTttFlags,
             CommandRegistry commandRegistry,
             Context context,
-            MediaTttChipControllerReceiver mediaTttChipControllerReceiver) {
+            @Main Executor mainExecutor) {
         if (!mediaTttFlags.isMediaTttEnabled()) {
             return Optional.empty();
         }
         return Optional.of(
-                new MediaTttCommandLineHelper(
-                        commandRegistry,
-                        context,
-                        mediaTttChipControllerReceiver));
+                new MediaTttCommandLineHelper(commandRegistry, context, mainExecutor));
     }
 
     /** Inject into NearbyMediaDevicesService. */
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 bbcbfba..26f31cd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -18,16 +18,13 @@
 
 import android.app.StatusBarManager
 import android.content.Context
-import android.graphics.Color
-import android.graphics.drawable.Icon
 import android.media.MediaRoute2Info
+import android.util.Log
 import androidx.annotation.VisibleForTesting
-import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
-import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
-import com.android.systemui.media.taptotransfer.sender.MoveCloserToEndCast
-import com.android.systemui.media.taptotransfer.sender.MoveCloserToStartCast
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast
+import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast
 import com.android.systemui.media.taptotransfer.sender.TransferFailed
 import com.android.systemui.media.taptotransfer.sender.TransferToReceiverTriggered
 import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceSucceeded
@@ -36,6 +33,7 @@
 import com.android.systemui.statusbar.commandline.Command
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import java.io.PrintWriter
+import java.util.concurrent.Executor
 import javax.inject.Inject
 
 /**
@@ -46,19 +44,33 @@
 class MediaTttCommandLineHelper @Inject constructor(
     commandRegistry: CommandRegistry,
     private val context: Context,
-    private val mediaTttChipControllerReceiver: MediaTttChipControllerReceiver,
+    @Main private val mainExecutor: Executor
 ) {
-   private val appIconDrawable =
-        Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also {
-            it.setTint(Color.YELLOW)
-        }
+    /**
+     * A map from a display state string typed in the command line to the display int it represents.
+     */
+    private val stateStringToStateInt: Map<String, Int> = mapOf(
+        AlmostCloseToStartCast::class.simpleName!!
+                to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+        AlmostCloseToEndCast::class.simpleName!!
+                to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+        TransferToReceiverTriggered::class.simpleName!!
+                to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
+        TransferToThisDeviceTriggered::class.simpleName!!
+                to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+        TransferToReceiverSucceeded::class.simpleName!!
+                to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
+        TransferToThisDeviceSucceeded::class.simpleName!!
+                to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
+        TransferFailed::class.simpleName!!
+                to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
+        FAR_FROM_RECEIVER_STATE
+                to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER
+    )
 
     init {
         commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() }
-        commandRegistry.registerCommand(
-            ADD_CHIP_COMMAND_RECEIVER_TAG) { AddChipCommandReceiver() }
-        commandRegistry.registerCommand(
-            REMOVE_CHIP_COMMAND_RECEIVER_TAG) { RemoveChipCommandReceiver() }
+        commandRegistry.registerCommand(RECEIVER_COMMAND) { ReceiverCommand() }
     }
 
     /** All commands for the sender device. */
@@ -68,41 +80,81 @@
                     .addFeature("feature")
                     .build()
 
+            val commandName = args[1]
+            @StatusBarManager.MediaTransferSenderState
+            val displayState = stateStringToStateInt[commandName]
+            if (displayState == null) {
+                pw.println("Invalid command name $commandName")
+                return
+            }
+
             val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE)
                     as StatusBarManager
             statusBarManager.updateMediaTapToTransferSenderDisplay(
-                    StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+                    displayState,
                     routeInfo,
-                    /* undoExecutor= */ null,
-                    /* undoCallback= */ null
+                getUndoExecutor(displayState),
+                getUndoCallback(displayState)
             )
-            // TODO(b/216318437): Migrate the rest of the callbacks to StatusBarManager.
+        }
+
+        private fun getUndoExecutor(
+            @StatusBarManager.MediaTransferSenderState displayState: Int
+        ): Executor? {
+            return if (isSucceededState(displayState)) {
+                mainExecutor
+            } else {
+                null
+            }
+        }
+
+        private fun getUndoCallback(
+            @StatusBarManager.MediaTransferSenderState displayState: Int
+        ): Runnable? {
+            return if (isSucceededState(displayState)) {
+                Runnable { Log.i(CLI_TAG, "Undo triggered for $displayState") }
+            } else {
+                null
+            }
+        }
+
+        private fun isSucceededState(
+            @StatusBarManager.MediaTransferSenderState displayState: Int
+        ): Boolean {
+            return displayState ==
+                    StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED ||
+                    displayState ==
+                    StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED
         }
 
         override fun help(pw: PrintWriter) {
-            pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND <deviceName> <chipStatus>")
+            pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND <deviceName> <chipState>")
         }
     }
 
-    /** A command to DISPLAY the media ttt chip on the RECEIVER device. */
-    inner class AddChipCommandReceiver : Command {
+    /** All commands for the receiver device. */
+    inner class ReceiverCommand : Command {
         override fun execute(pw: PrintWriter, args: List<String>) {
-            mediaTttChipControllerReceiver.displayChip(
-                ChipStateReceiver(appIconDrawable, APP_ICON_CONTENT_DESCRIPTION)
-            )
+            val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE)
+                    as StatusBarManager
+            when(val commandName = args[0]) {
+                CLOSE_TO_SENDER_STATE ->
+                    statusBarManager.updateMediaTapToTransferReceiverDisplay(
+                        StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
+                        routeInfo
+                    )
+                FAR_FROM_SENDER_STATE ->
+                    statusBarManager.updateMediaTapToTransferReceiverDisplay(
+                        StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
+                        routeInfo
+                    )
+                else ->
+                    pw.println("Invalid command name $commandName")
+            }
         }
-        override fun help(pw: PrintWriter) {
-            pw.println("Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_RECEIVER_TAG")
-        }
-    }
 
-    /** A command to REMOVE the media ttt chip on the RECEIVER device. */
-    inner class RemoveChipCommandReceiver : Command {
-        override fun execute(pw: PrintWriter, args: List<String>) {
-            mediaTttChipControllerReceiver.removeChip()
-        }
         override fun help(pw: PrintWriter) {
-            pw.println("Usage: adb shell cmd statusbar $REMOVE_CHIP_COMMAND_RECEIVER_TAG")
+            pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND <chipState>")
         }
     }
 }
@@ -110,29 +162,15 @@
 @VisibleForTesting
 const val SENDER_COMMAND = "media-ttt-chip-sender"
 @VisibleForTesting
-const val REMOVE_CHIP_COMMAND_SENDER_TAG = "media-ttt-chip-remove-sender"
+const val RECEIVER_COMMAND = "media-ttt-chip-receiver"
 @VisibleForTesting
-const val ADD_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-add-receiver"
+const val FAR_FROM_RECEIVER_STATE = "FarFromReceiver"
 @VisibleForTesting
-const val REMOVE_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-remove-receiver"
+const val CLOSE_TO_SENDER_STATE = "CloseToSender"
 @VisibleForTesting
-val MOVE_CLOSER_TO_START_CAST_COMMAND_NAME = MoveCloserToStartCast::class.simpleName!!
-@VisibleForTesting
-val MOVE_CLOSER_TO_END_CAST_COMMAND_NAME = MoveCloserToEndCast::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME = TransferToReceiverTriggered::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME =
-    TransferToThisDeviceTriggered::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_TO_RECEIVER_SUCCEEDED_COMMAND_NAME = TransferToReceiverSucceeded::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_TO_THIS_DEVICE_SUCCEEDED_COMMAND_NAME =
-    TransferToThisDeviceSucceeded::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_FAILED_COMMAND_NAME = TransferFailed::class.simpleName!!
-@VisibleForTesting
-val NO_LONGER_CLOSE_TO_RECEIVER_COMMAND_NAME = "NoLongerCloseToReceiver"
+const val FAR_FROM_SENDER_STATE = "FarFromSender"
+private const val CLI_TAG = "MediaTransferCli"
 
-private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon"
-private const val TAG = "MediaTapToTransferCli"
+private val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
+    .addFeature("feature")
+    .build()
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 1780954..2d3ca5f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -16,12 +16,18 @@
 
 package com.android.systemui.media.taptotransfer.receiver
 
+import android.app.StatusBarManager
 import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.Icon
+import android.media.MediaRoute2Info
+import android.util.Log
 import android.view.ViewGroup
 import android.view.WindowManager
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
+import com.android.systemui.statusbar.CommandQueue
 import javax.inject.Inject
 
 /**
@@ -31,13 +37,49 @@
  */
 @SysUISingleton
 class MediaTttChipControllerReceiver @Inject constructor(
+    commandQueue: CommandQueue,
     context: Context,
     windowManager: WindowManager,
 ) : MediaTttChipControllerCommon<ChipStateReceiver>(
     context, windowManager, R.layout.media_ttt_chip_receiver
 ) {
+    // TODO(b/216141279): Use app icon from media route info instead of this fake one.
+    private val fakeAppIconDrawable =
+        Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also {
+            it.setTint(Color.YELLOW)
+        }
+
+    private val commandQueueCallbacks = object : CommandQueue.Callbacks {
+        override fun updateMediaTapToTransferReceiverDisplay(
+            @StatusBarManager.MediaTransferReceiverState displayState: Int,
+            routeInfo: MediaRoute2Info
+        ) {
+            this@MediaTttChipControllerReceiver.updateMediaTapToTransferReceiverDisplay(
+                displayState, routeInfo
+            )
+        }
+    }
+
+    init {
+        commandQueue.addCallback(commandQueueCallbacks)
+    }
+
+    private fun updateMediaTapToTransferReceiverDisplay(
+        @StatusBarManager.MediaTransferReceiverState displayState: Int,
+        routeInfo: MediaRoute2Info
+    ) {
+        when(displayState) {
+            StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER ->
+                displayChip(ChipStateReceiver(fakeAppIconDrawable, routeInfo.name.toString()))
+            StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER -> removeChip()
+            else ->
+                Log.e(RECEIVER_TAG, "Unhandled MediaTransferReceiverState $displayState")
+        }
+    }
 
     override fun updateChipView(chipState: ChipStateReceiver, currentChipView: ViewGroup) {
         setIcon(chipState, currentChipView)
     }
 }
+
+private const val RECEIVER_TAG = "MediaTapToTransferReceiver"
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index 118a04c..05baf78 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -59,7 +59,7 @@
  *
  * @property otherDeviceName the name of the other device involved in the transfer.
  */
-class MoveCloserToStartCast(
+class AlmostCloseToStartCast(
     appIconDrawable: Drawable,
     appIconContentDescription: String,
     private val otherDeviceName: String,
@@ -76,7 +76,7 @@
  *
  * @property otherDeviceName the name of the other device involved in the transfer.
  */
-class MoveCloserToEndCast(
+class AlmostCloseToEndCast(
     appIconDrawable: Drawable,
     appIconContentDescription: String,
     private val otherDeviceName: String,
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index c510e35..d1790d2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -21,6 +21,7 @@
 import android.graphics.Color
 import android.graphics.drawable.Icon
 import android.media.MediaRoute2Info
+import android.util.Log
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
@@ -38,9 +39,9 @@
  */
 @SysUISingleton
 class MediaTttChipControllerSender @Inject constructor(
+    commandQueue: CommandQueue,
     context: Context,
     windowManager: WindowManager,
-    private val commandQueue: CommandQueue
 ) : MediaTttChipControllerCommon<ChipStateSender>(
     context, windowManager, R.layout.media_ttt_chip
 ) {
@@ -50,25 +51,80 @@
             it.setTint(Color.YELLOW)
         }
 
-    private val commandQueueCallback = object : CommandQueue.Callbacks {
+    private val commandQueueCallbacks = object : CommandQueue.Callbacks {
         override fun updateMediaTapToTransferSenderDisplay(
                 @StatusBarManager.MediaTransferSenderState displayState: Int,
                 routeInfo: MediaRoute2Info,
                 undoCallback: IUndoMediaTransferCallback?
         ) {
-            // TODO(b/216318437): Trigger displayChip with the right state based on displayState.
-            displayChip(
-                MoveCloserToStartCast(
-                    // TODO(b/217418566): This app icon content description is incorrect --
-                    //   routeInfo.name is the name of the device, not the name of the app.
-                    fakeAppIconDrawable, routeInfo.name.toString(), routeInfo.name.toString()
-                )
+            this@MediaTttChipControllerSender.updateMediaTapToTransferSenderDisplay(
+                displayState, routeInfo, undoCallback
             )
         }
     }
 
     init {
-        commandQueue.addCallback(commandQueueCallback)
+        commandQueue.addCallback(commandQueueCallbacks)
+    }
+
+    private fun updateMediaTapToTransferSenderDisplay(
+        @StatusBarManager.MediaTransferSenderState displayState: Int,
+        routeInfo: MediaRoute2Info,
+        undoCallback: IUndoMediaTransferCallback?
+    ) {
+        // TODO(b/217418566): This app icon content description is incorrect --
+        //   routeInfo.name is the name of the device, not the name of the app.
+        val appIconContentDescription = routeInfo.name.toString()
+        val otherDeviceName = routeInfo.name.toString()
+        val chipState = when(displayState) {
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST ->
+                AlmostCloseToStartCast(
+                    fakeAppIconDrawable, appIconContentDescription, otherDeviceName
+                )
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST ->
+                AlmostCloseToEndCast(
+                    fakeAppIconDrawable, appIconContentDescription, otherDeviceName
+                )
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED ->
+                TransferToReceiverTriggered(
+                    fakeAppIconDrawable, appIconContentDescription, otherDeviceName
+                )
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED ->
+                TransferToThisDeviceTriggered(
+                    fakeAppIconDrawable, appIconContentDescription
+                )
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED ->
+                TransferToReceiverSucceeded(
+                    fakeAppIconDrawable,
+                    appIconContentDescription,
+                    otherDeviceName,
+                    undoCallback
+                )
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED ->
+                TransferToThisDeviceSucceeded(
+                    fakeAppIconDrawable,
+                    appIconContentDescription,
+                    otherDeviceName,
+                    undoCallback
+                )
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED ->
+                TransferFailed(
+                    fakeAppIconDrawable, appIconContentDescription
+                )
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> {
+                removeChip()
+                null
+            }
+            else -> {
+                Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState")
+                null
+            }
+        }
+
+        chipState?.let {
+            displayChip(it)
+        }
     }
 
     /** Displays the chip view for the given state. */
@@ -97,3 +153,5 @@
             if (showFailure) { View.VISIBLE } else { View.GONE }
     }
 }
+
+const val SENDER_TAG = "MediaTapToTransferSender"
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index 42b7cc3..5e9edb7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -18,6 +18,8 @@
 
 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
 
+import static com.android.systemui.accessibility.SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON;
+import static com.android.systemui.accessibility.SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
 
@@ -39,6 +41,8 @@
 
 import com.android.systemui.Dumpable;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
@@ -70,13 +74,16 @@
 @SysUISingleton
 public final class NavBarHelper implements
         AccessibilityButtonModeObserver.ModeChangedListener,
+        AccessibilityButtonTargetsObserver.TargetsChangedListener,
         OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
         Dumpable {
     private final AccessibilityManager mAccessibilityManager;
     private final Lazy<AssistManager> mAssistManagerLazy;
     private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
     private final UserTracker mUserTracker;
+    private final SystemActions mSystemActions;
     private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
+    private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
     private final List<NavbarTaskbarStateUpdater> mA11yEventListeners = new ArrayList<>();
     private final Context mContext;
     private ContentResolver mContentResolver;
@@ -84,12 +91,13 @@
     private boolean mLongPressHomeEnabled;
     private boolean mAssistantTouchGestureEnabled;
     private int mNavBarMode;
+    private int mA11yButtonState;
 
     private final ContentObserver mAssistContentObserver = new ContentObserver(
             new Handler(Looper.getMainLooper())) {
         @Override
         public void onChange(boolean selfChange, Uri uri) {
-            updateAssitantAvailability();
+            updateAssistantAvailability();
         }
     };
 
@@ -100,8 +108,9 @@
      */
     @Inject
     public NavBarHelper(Context context, AccessibilityManager accessibilityManager,
-            AccessibilityManagerWrapper accessibilityManagerWrapper,
             AccessibilityButtonModeObserver accessibilityButtonModeObserver,
+            AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
+            SystemActions systemActions,
             OverviewProxyService overviewProxyService,
             Lazy<AssistManager> assistManagerLazy,
             Lazy<Optional<StatusBar>> statusBarOptionalLazy,
@@ -114,11 +123,14 @@
         mAssistManagerLazy = assistManagerLazy;
         mStatusBarOptionalLazy = statusBarOptionalLazy;
         mUserTracker = userTracker;
-        accessibilityManagerWrapper.addCallback(
+        mSystemActions = systemActions;
+        accessibilityManager.addAccessibilityServicesStateChangeListener(
                 accessibilityManager1 -> NavBarHelper.this.dispatchA11yEventUpdate());
         mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
+        mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
 
         mAccessibilityButtonModeObserver.addListener(this);
+        mAccessibilityButtonTargetsObserver.addListener(this);
         mNavBarMode = navigationModeController.addListener(this);
         overviewProxyService.addCallback(this);
         dumpManager.registerDumpable(this);
@@ -134,7 +146,7 @@
         mContentResolver.registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
                 false, mAssistContentObserver, UserHandle.USER_ALL);
-        updateAssitantAvailability();
+        updateAssistantAvailability();
     }
 
     public void destroy() {
@@ -168,9 +180,63 @@
 
     @Override
     public void onAccessibilityButtonModeChanged(int mode) {
+        updateA11yState();
         dispatchA11yEventUpdate();
     }
 
+    @Override
+    public void onAccessibilityButtonTargetsChanged(String targets) {
+        updateA11yState();
+        dispatchA11yEventUpdate();
+    }
+
+    /**
+     * Updates the current accessibility button state.
+     */
+    private void updateA11yState() {
+        final int prevState = mA11yButtonState;
+        final boolean clickable;
+        final boolean longClickable;
+        if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
+                == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
+            // If accessibility button is floating menu mode, click and long click state should be
+            // disabled.
+            clickable = false;
+            longClickable = false;
+            mA11yButtonState = 0;
+        } else {
+            // AccessibilityManagerService resolves services for the current user since the local
+            // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS
+            // permission
+            final List<String> a11yButtonTargets =
+                    mAccessibilityManager.getAccessibilityShortcutTargets(
+                            AccessibilityManager.ACCESSIBILITY_BUTTON);
+            final int requestingServices = a11yButtonTargets.size();
+
+            clickable = requestingServices >= 1;
+            longClickable = requestingServices >= 2;
+            mA11yButtonState = (clickable ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
+                    | (longClickable ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
+        }
+
+        // Update the system actions if the state has changed
+        if (prevState != mA11yButtonState) {
+            updateSystemAction(clickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON);
+            updateSystemAction(longClickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER);
+        }
+    }
+
+    /**
+     * Registers/unregisters the given system action id.
+     */
+    private void updateSystemAction(boolean register, int actionId) {
+        if (register) {
+            mSystemActions.register(actionId);
+        } else {
+            mSystemActions.unregister(actionId);
+        }
+    }
+
     /**
      * See {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
      * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
@@ -179,32 +245,17 @@
      *         a11y button in the navbar
      */
     public int getA11yButtonState() {
-        // AccessibilityManagerService resolves services for the current user since the local
-        // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
-        final List<String> a11yButtonTargets =
-                mAccessibilityManager.getAccessibilityShortcutTargets(
-                        AccessibilityManager.ACCESSIBILITY_BUTTON);
-        final int requestingServices = a11yButtonTargets.size();
-
-        // If accessibility button is floating menu mode, click and long click state should be
-        // disabled.
-        if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
-                == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
-            return 0;
-        }
-
-        return (requestingServices >= 1 ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
-                | (requestingServices >= 2 ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
+        return mA11yButtonState;
     }
 
     @Override
     public void onConnectionChanged(boolean isConnected) {
         if (isConnected) {
-            updateAssitantAvailability();
+            updateAssistantAvailability();
         }
     }
 
-    private void updateAssitantAvailability() {
+    private void updateAssistantAvailability() {
         boolean assistantAvailableForUser = mAssistManagerLazy.get()
                 .getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
         boolean longPressDefault = mContext.getResources().getBoolean(
@@ -236,7 +287,7 @@
     @Override
     public void onNavigationModeChanged(int mode) {
         mNavBarMode = mode;
-        updateAssitantAvailability();
+        updateAssistantAvailability();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 1bef32a..d16c019 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -17,7 +17,7 @@
 package com.android.systemui.navigationbar;
 
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
-import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN;
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.WindowType;
@@ -110,7 +110,6 @@
 import com.android.internal.view.AppearanceRegion;
 import com.android.systemui.R;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
-import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -122,7 +121,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.rotation.RotationButton;
 import com.android.systemui.shared.rotation.RotationButtonController;
@@ -192,7 +190,6 @@
     private final Optional<LegacySplitScreen> mSplitScreenOptional;
     private final Optional<Recents> mRecentsOptional;
     private final Optional<BackAnimation> mBackAnimation;
-    private final SystemActions mSystemActions;
     private final Handler mHandler;
     private final NavigationBarOverlayController mNavbarOverlayController;
     private final UiEventLogger mUiEventLogger;
@@ -307,7 +304,7 @@
             new NavBarHelper.NavbarTaskbarStateUpdater() {
                 @Override
                 public void updateAccessibilityServicesState() {
-                    updateAcessibilityStateFlags();
+                    updateAccessibilityStateFlags();
                 }
 
                 @Override
@@ -495,12 +492,10 @@
             ShadeController shadeController,
             NotificationRemoteInputManager notificationRemoteInputManager,
             NotificationShadeDepthController notificationShadeDepthController,
-            SystemActions systemActions,
             @Main Handler mainHandler,
             NavigationBarOverlayController navbarOverlayController,
             UiEventLogger uiEventLogger,
             NavBarHelper navBarHelper,
-            UserTracker userTracker,
             LightBarController mainLightBarController,
             LightBarController.Factory lightBarControllerFactory,
             AutoHideController mainAutoHideController,
@@ -528,7 +523,6 @@
         mSplitScreenOptional = splitScreenOptional;
         mRecentsOptional = recentsOptional;
         mBackAnimation = backAnimation;
-        mSystemActions = systemActions;
         mHandler = mainHandler;
         mNavbarOverlayController = navbarOverlayController;
         mUiEventLogger = uiEventLogger;
@@ -646,7 +640,7 @@
         notifyNavigationBarScreenOn();
 
         mOverviewProxyService.addCallback(mOverviewProxyListener);
-        updateSystemUiStateFlags(-1);
+        updateSystemUiStateFlags();
 
         // Currently there is no accelerometer sensor on non-default display.
         if (mIsOnDefaultDisplay) {
@@ -904,7 +898,7 @@
             mNavigationBarView.setNavigationIconHints(hints);
         }
         checkBarModes();
-        updateSystemUiStateFlags(-1);
+        updateSystemUiStateFlags();
     }
 
     @Override
@@ -914,7 +908,7 @@
                 && window == StatusBarManager.WINDOW_NAVIGATION_BAR
                 && mNavigationBarWindowState != state) {
             mNavigationBarWindowState = state;
-            updateSystemUiStateFlags(-1);
+            updateSystemUiStateFlags();
             mShowOrientedHandleForImmersiveMode = state == WINDOW_STATE_HIDDEN;
             if (mOrientationHandle != null
                     && mStartingQuickSwitchRotation != -1) {
@@ -993,7 +987,7 @@
         if (mBehavior != behavior) {
             mBehavior = behavior;
             mNavigationBarView.setBehavior(behavior);
-            updateSystemUiStateFlags(-1);
+            updateSystemUiStateFlags();
         }
     }
 
@@ -1160,7 +1154,7 @@
         ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
         accessibilityButton.setOnClickListener(this::onAccessibilityClick);
         accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
-        updateAcessibilityStateFlags();
+        updateAccessibilityStateFlags();
 
         ButtonDispatcher imeSwitcherButton = mNavigationBarView.getImeSwitchButton();
         imeSwitcherButton.setOnClickListener(this::onImeSwitcherClick);
@@ -1386,21 +1380,18 @@
         return true;
     }
 
-    void updateAcessibilityStateFlags() {
-        int a11yFlags = mNavBarHelper.getA11yButtonState();
-
+    void updateAccessibilityStateFlags() {
         if (mNavigationBarView != null) {
+            int a11yFlags = mNavBarHelper.getA11yButtonState();
             boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
             boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
             mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
         }
-        updateSystemUiStateFlags(a11yFlags);
+        updateSystemUiStateFlags();
     }
 
-    public void updateSystemUiStateFlags(int a11yFlags) {
-        if (a11yFlags < 0) {
-            a11yFlags = mNavBarHelper.getA11yButtonState();
-        }
+    public void updateSystemUiStateFlags() {
+        int a11yFlags = mNavBarHelper.getA11yButtonState();
         boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
         boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
 
@@ -1410,20 +1401,10 @@
                 .setFlag(SYSUI_STATE_IME_SHOWING,
                         (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0)
                 .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING,
-                        (mNavigationIconHints & NAVIGATION_HINT_IME_SHOWN) != 0)
+                        (mNavigationIconHints & NAVIGATION_HINT_IME_SWITCHER_SHOWN) != 0)
                 .setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
                         allowSystemGestureIgnoringBarVisibility())
                 .commitUpdate(mDisplayId);
-        registerAction(clickable, SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON);
-        registerAction(longClickable, SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER);
-    }
-
-    private void registerAction(boolean register, int actionId) {
-        if (register) {
-            mSystemActions.register(actionId);
-        } else {
-            mSystemActions.unregister(actionId);
-        }
     }
 
     private void updateAssistantEntrypoints(boolean assistantAvailable) {
@@ -1641,7 +1622,7 @@
             }
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 // The accessibility settings may be different for the new user
-                updateAcessibilityStateFlags();
+                updateAccessibilityStateFlags();
             }
         }
     };
@@ -1673,12 +1654,10 @@
         private final ShadeController mShadeController;
         private final NotificationRemoteInputManager mNotificationRemoteInputManager;
         private final NotificationShadeDepthController mNotificationShadeDepthController;
-        private final SystemActions mSystemActions;
         private final Handler mMainHandler;
         private final NavigationBarOverlayController mNavbarOverlayController;
         private final UiEventLogger mUiEventLogger;
         private final NavBarHelper mNavBarHelper;
-        private final UserTracker mUserTracker;
         private final LightBarController mMainLightBarController;
         private final LightBarController.Factory mLightBarControllerFactory;
         private final AutoHideController mMainAutoHideController;
@@ -1707,12 +1686,10 @@
                 ShadeController shadeController,
                 NotificationRemoteInputManager notificationRemoteInputManager,
                 NotificationShadeDepthController notificationShadeDepthController,
-                SystemActions systemActions,
                 @Main Handler mainHandler,
                 NavigationBarOverlayController navbarOverlayController,
                 UiEventLogger uiEventLogger,
                 NavBarHelper navBarHelper,
-                UserTracker userTracker,
                 LightBarController mainLightBarController,
                 LightBarController.Factory lightBarControllerFactory,
                 AutoHideController mainAutoHideController,
@@ -1738,12 +1715,10 @@
             mShadeController = shadeController;
             mNotificationRemoteInputManager = notificationRemoteInputManager;
             mNotificationShadeDepthController = notificationShadeDepthController;
-            mSystemActions = systemActions;
             mMainHandler = mainHandler;
             mNavbarOverlayController = navbarOverlayController;
             mUiEventLogger = uiEventLogger;
             mNavBarHelper = navBarHelper;
-            mUserTracker = userTracker;
             mMainLightBarController = mainLightBarController;
             mLightBarControllerFactory = lightBarControllerFactory;
             mMainAutoHideController = mainAutoHideController;
@@ -1763,9 +1738,9 @@
                     mSysUiFlagsContainer, mBroadcastDispatcher, mCommandQueue, mPipOptional,
                     mSplitScreenOptional, mRecentsOptional, mStatusBarOptionalLazy,
                     mShadeController, mNotificationRemoteInputManager,
-                    mNotificationShadeDepthController, mSystemActions, mMainHandler,
+                    mNotificationShadeDepthController, mMainHandler,
                     mNavbarOverlayController, mUiEventLogger, mNavBarHelper,
-                    mUserTracker, mMainLightBarController, mLightBarControllerFactory,
+                    mMainLightBarController, mLightBarControllerFactory,
                     mMainAutoHideController, mAutoHideControllerFactory, mTelecomManagerOptional,
                     mInputMethodManager, mBackAnimation);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 2dd89f3..593b278c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -774,11 +774,12 @@
         updateRecentsIcon();
 
         boolean isImeRenderingNavButtons = isGesturalMode(mNavBarMode)
-                && mImeCanRenderGesturalNavButtons;
+                && mImeCanRenderGesturalNavButtons
+                && (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0;
 
         // Update IME button visibility, a11y and rotate button always overrides the appearance
         boolean disableImeSwitcher =
-                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0
+                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN) == 0
                 || isImeRenderingNavButtons;
         mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher, !disableImeSwitcher);
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index ec15b24..75a3df7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -17,7 +17,7 @@
 package com.android.systemui.navigationbar;
 
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
-import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.InsetsState.containsType;
@@ -293,7 +293,7 @@
                 .setFlag(SYSUI_STATE_IME_SHOWING,
                         (mNavigationIconHints & NAVIGATION_HINT_BACK_ALT) != 0)
                 .setFlag(SYSUI_STATE_IME_SWITCHER_SHOWING,
-                        (mNavigationIconHints & NAVIGATION_HINT_IME_SHOWN) != 0)
+                        (mNavigationIconHints & NAVIGATION_HINT_IME_SWITCHER_SHOWN) != 0)
                 .setFlag(SYSUI_STATE_OVERVIEW_DISABLED,
                         (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0)
                 .setFlag(SYSUI_STATE_HOME_DISABLED,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
new file mode 100644
index 0000000..58ebe89
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs
+
+import android.app.IActivityManager
+import android.app.IForegroundServiceObserver
+import android.content.Context
+import android.content.pm.PackageManager
+import android.graphics.drawable.Drawable
+import android.os.IBinder
+import android.os.PowerExemptionManager
+import android.os.RemoteException
+import android.provider.DeviceConfig.NAMESPACE_SYSTEMUI
+import android.text.format.DateUtils
+import android.util.ArrayMap
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.GuardedBy
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED
+import com.android.systemui.R
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.DeviceConfigProxy
+import com.android.systemui.util.time.SystemClock
+import java.util.Objects
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlin.math.max
+
+class FgsManagerController @Inject constructor(
+    private val context: Context,
+    @Main private val mainExecutor: Executor,
+    @Background private val backgroundExecutor: Executor,
+    private val systemClock: SystemClock,
+    private val activityManager: IActivityManager,
+    private val packageManager: PackageManager,
+    private val deviceConfigProxy: DeviceConfigProxy,
+    private val dialogLaunchAnimator: DialogLaunchAnimator
+) : IForegroundServiceObserver.Stub() {
+
+    companion object {
+        private val LOG_TAG = FgsManagerController::class.java.simpleName
+    }
+
+    private var isAvailable = false
+
+    private val lock = Any()
+
+    @GuardedBy("lock")
+    var initialized = false
+
+    @GuardedBy("lock")
+    private val runningServiceTokens = mutableMapOf<UserPackage, StartTimeAndTokens>()
+
+    @GuardedBy("lock")
+    private var dialog: SystemUIDialog? = null
+
+    @GuardedBy("lock")
+    private val appListAdapter: AppListAdapter = AppListAdapter()
+
+    @GuardedBy("lock")
+    private var runningApps: ArrayMap<UserPackage, RunningApp> = ArrayMap()
+
+    interface OnNumberOfPackagesChangedListener {
+        fun onNumberOfPackagesChanged(numPackages: Int)
+    }
+
+    interface OnDialogDismissedListener {
+        fun onDialogDismissed()
+    }
+
+    fun init() {
+        synchronized(lock) {
+            if (initialized) {
+                return
+            }
+            try {
+                activityManager.registerForegroundServiceObserver(this)
+            } catch (e: RemoteException) {
+                e.rethrowFromSystemServer()
+            }
+
+            deviceConfigProxy.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI,
+                    backgroundExecutor) {
+                isAvailable = it.getBoolean(TASK_MANAGER_ENABLED, isAvailable)
+            }
+
+            isAvailable = deviceConfigProxy
+                    .getBoolean(NAMESPACE_SYSTEMUI, TASK_MANAGER_ENABLED, true)
+
+            initialized = true
+        }
+    }
+
+    override fun onForegroundStateChanged(
+        token: IBinder,
+        packageName: String,
+        userId: Int,
+        isForeground: Boolean
+    ) {
+        synchronized(lock) {
+            val numPackagesBefore = getNumRunningPackagesLocked()
+            val userPackageKey = UserPackage(userId, packageName)
+            if (isForeground) {
+                runningServiceTokens.getOrPut(userPackageKey, { StartTimeAndTokens(systemClock) })
+                        .addToken(token)
+            } else {
+                if (runningServiceTokens[userPackageKey]?.also {
+                            it.removeToken(token) }?.isEmpty() == true) {
+                    runningServiceTokens.remove(userPackageKey)
+                }
+            }
+
+            val numPackagesAfter = getNumRunningPackagesLocked()
+
+            if (numPackagesAfter != numPackagesBefore) {
+                onNumberOfPackagesChangedListeners.forEach {
+                    backgroundExecutor.execute { it.onNumberOfPackagesChanged(numPackagesAfter) }
+                }
+            }
+
+            updateAppItemsLocked()
+        }
+    }
+
+    @GuardedBy("lock")
+    val onNumberOfPackagesChangedListeners: MutableSet<OnNumberOfPackagesChangedListener> =
+            mutableSetOf()
+
+    @GuardedBy("lock")
+    val onDialogDismissedListeners: MutableSet<OnDialogDismissedListener> = mutableSetOf()
+
+    fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) {
+        synchronized(lock) {
+            onNumberOfPackagesChangedListeners.add(listener)
+        }
+    }
+
+    fun removeOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) {
+        synchronized(lock) {
+            onNumberOfPackagesChangedListeners.remove(listener)
+        }
+    }
+
+    fun addOnDialogDismissedListener(listener: OnDialogDismissedListener) {
+        synchronized(lock) {
+            onDialogDismissedListeners.add(listener)
+        }
+    }
+
+    fun removeOnDialogDismissedListener(listener: OnDialogDismissedListener) {
+        synchronized(lock) {
+            onDialogDismissedListeners.remove(listener)
+        }
+    }
+
+    fun isAvailable(): Boolean {
+        return isAvailable
+    }
+
+    fun getNumRunningPackages(): Int {
+        synchronized(lock) {
+            return getNumRunningPackagesLocked()
+        }
+    }
+
+    private fun getNumRunningPackagesLocked() =
+            runningServiceTokens.keys.count { it.uiControl != UIControl.HIDE_ENTRY }
+
+    fun shouldUpdateFooterVisibility() = dialog == null
+
+    fun showDialog(viewLaunchedFrom: View?) {
+        synchronized(lock) {
+            if (dialog == null) {
+
+                val dialog = SystemUIDialog(context)
+                dialog.setTitle(R.string.fgs_manager_dialog_title)
+
+                val dialogContext = dialog.context
+
+                val recyclerView = RecyclerView(dialogContext)
+                recyclerView.layoutManager = LinearLayoutManager(dialogContext)
+                recyclerView.adapter = appListAdapter
+
+                dialog.setView(recyclerView)
+
+                this.dialog = dialog
+
+                dialog.setOnDismissListener {
+                    synchronized(lock) {
+                        this.dialog = null
+                        updateAppItemsLocked()
+                    }
+                    onDialogDismissedListeners.forEach {
+                        mainExecutor.execute(it::onDialogDismissed)
+                    }
+                }
+
+                mainExecutor.execute {
+                    viewLaunchedFrom
+                            ?.let { dialogLaunchAnimator.showFromView(dialog, it) } ?: dialog.show()
+                }
+
+                backgroundExecutor.execute {
+                    synchronized(lock) {
+                        updateAppItemsLocked()
+                    }
+                }
+            }
+        }
+    }
+
+    @GuardedBy("lock")
+    private fun updateAppItemsLocked() {
+        if (dialog == null) {
+            runningApps.clear()
+            return
+        }
+
+        val addedPackages = runningServiceTokens.keys.filter {
+            it.uiControl != UIControl.HIDE_ENTRY && runningApps[it]?.stopped != true
+        }
+        val removedPackages = runningApps.keys.filter { !runningServiceTokens.containsKey(it) }
+
+        addedPackages.forEach {
+            val ai = packageManager.getApplicationInfoAsUser(it.packageName, 0, it.userId)
+            runningApps[it] = RunningApp(it.userId, it.packageName,
+                    runningServiceTokens[it]!!.startTime, it.uiControl,
+                    ai.loadLabel(packageManager), ai.loadIcon(packageManager))
+        }
+
+        removedPackages.forEach { pkg ->
+            val ra = runningApps[pkg]!!
+            val ra2 = ra.copy().also {
+                it.stopped = true
+                it.appLabel = ra.appLabel
+                it.icon = ra.icon
+            }
+            runningApps[pkg] = ra2
+        }
+
+        mainExecutor.execute {
+            appListAdapter
+                    .setData(runningApps.values.toList().sortedByDescending { it.timeStarted })
+        }
+    }
+
+    private fun stopPackage(userId: Int, packageName: String) {
+        activityManager.stopAppForUser(packageName, userId)
+    }
+
+    private inner class AppListAdapter : RecyclerView.Adapter<AppItemViewHolder>() {
+        private val lock = Any()
+
+        @GuardedBy("lock")
+        private var data: List<RunningApp> = listOf()
+
+        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppItemViewHolder {
+            return AppItemViewHolder(LayoutInflater.from(parent.context)
+                    .inflate(R.layout.fgs_manager_app_item, parent, false))
+        }
+
+        override fun onBindViewHolder(holder: AppItemViewHolder, position: Int) {
+            var runningApp: RunningApp
+            synchronized(lock) {
+                runningApp = data[position]
+            }
+            with(holder) {
+                iconView.setImageDrawable(runningApp.icon)
+                appLabelView.text = runningApp.appLabel
+                durationView.text = DateUtils.formatDuration(
+                        max(systemClock.elapsedRealtime() - runningApp.timeStarted, 60000),
+                        DateUtils.LENGTH_MEDIUM)
+                stopButton.setOnClickListener {
+                    stopButton.setText(R.string.fgs_manager_app_item_stop_button_stopped_label)
+                    stopPackage(runningApp.userId, runningApp.packageName)
+                }
+                if (runningApp.uiControl == UIControl.HIDE_BUTTON) {
+                    stopButton.visibility = View.INVISIBLE
+                }
+                if (runningApp.stopped) {
+                    stopButton.isEnabled = false
+                    stopButton.setText(R.string.fgs_manager_app_item_stop_button_stopped_label)
+                    durationView.visibility = View.GONE
+                } else {
+                    stopButton.isEnabled = true
+                    stopButton.setText(R.string.fgs_manager_app_item_stop_button_label)
+                    durationView.visibility = View.VISIBLE
+                }
+            }
+        }
+
+        override fun getItemCount(): Int {
+            return data.size
+        }
+
+        fun setData(newData: List<RunningApp>) {
+            var oldData = data
+            data = newData
+
+            DiffUtil.calculateDiff(object : DiffUtil.Callback() {
+                override fun getOldListSize(): Int {
+                    return oldData.size
+                }
+
+                override fun getNewListSize(): Int {
+                    return newData.size
+                }
+
+                override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int):
+                        Boolean {
+                    return oldData[oldItemPosition] == newData[newItemPosition]
+                }
+
+                override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int):
+                        Boolean {
+                    return oldData[oldItemPosition].stopped == newData[newItemPosition].stopped
+                }
+            }).dispatchUpdatesTo(this)
+        }
+    }
+
+    private inner class UserPackage(
+        val userId: Int,
+        val packageName: String
+    ) {
+        val uiControl: UIControl by lazy {
+            val uid = packageManager.getPackageUidAsUser(packageName, userId)
+
+            when (activityManager.getBackgroundRestrictionExemptionReason(uid)) {
+                PowerExemptionManager.REASON_SYSTEM_UID,
+                PowerExemptionManager.REASON_DEVICE_DEMO_MODE -> UIControl.HIDE_ENTRY
+
+                PowerExemptionManager.REASON_DEVICE_OWNER,
+                PowerExemptionManager.REASON_PROFILE_OWNER,
+                PowerExemptionManager.REASON_PROC_STATE_PERSISTENT,
+                PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI,
+                PowerExemptionManager.REASON_ROLE_DIALER,
+                PowerExemptionManager.REASON_SYSTEM_MODULE -> UIControl.HIDE_BUTTON
+                else -> UIControl.NORMAL
+            }
+        }
+
+        override fun equals(other: Any?): Boolean {
+            if (other !is UserPackage) {
+                return false
+            }
+            return other.packageName == packageName && other.userId == userId
+        }
+
+        override fun hashCode(): Int = Objects.hash(userId, packageName)
+    }
+
+    private data class StartTimeAndTokens(
+        val systemClock: SystemClock
+    ) {
+        val startTime = systemClock.elapsedRealtime()
+        val tokens = mutableSetOf<IBinder>()
+
+        fun addToken(token: IBinder) {
+            tokens.add(token)
+        }
+
+        fun removeToken(token: IBinder) {
+            tokens.remove(token)
+        }
+
+        fun isEmpty(): Boolean {
+            return tokens.isEmpty()
+        }
+    }
+
+    private class AppItemViewHolder(parent: View) : RecyclerView.ViewHolder(parent) {
+        val appLabelView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_label)
+        val durationView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_duration)
+        val iconView: ImageView = parent.requireViewById(R.id.fgs_manager_app_item_icon)
+        val stopButton: Button = parent.requireViewById(R.id.fgs_manager_app_item_stop_button)
+    }
+
+    private data class RunningApp(
+        val userId: Int,
+        val packageName: String,
+        val timeStarted: Long,
+        val uiControl: UIControl
+    ) {
+        constructor(
+            userId: Int,
+            packageName: String,
+            timeStarted: Long,
+            uiControl: UIControl,
+            appLabel: CharSequence,
+            icon: Drawable
+        ) : this(userId, packageName, timeStarted, uiControl) {
+            this.appLabel = appLabel
+            this.icon = icon
+        }
+
+        // variables to keep out of the generated equals()
+        var appLabel: CharSequence = ""
+        var icon: Drawable? = null
+        var stopped = false
+    }
+
+    private enum class UIControl {
+        NORMAL, HIDE_BUTTON, HIDE_ENTRY
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
index 082de16..55d4a53 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
@@ -16,13 +16,9 @@
 
 package com.android.systemui.qs;
 
-import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
-
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED;
 import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FGS_MANAGER_FOOTER_VIEW;
 
 import android.content.Context;
-import android.provider.DeviceConfig;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -30,8 +26,6 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.fgsmanager.FgsManagerDialogFactory;
-import com.android.systemui.statusbar.policy.RunningFgsController;
 
 import java.util.concurrent.Executor;
 
@@ -41,24 +35,25 @@
 /**
  * Footer entry point for the foreground service manager
  */
-public class QSFgsManagerFooter implements View.OnClickListener {
+public class QSFgsManagerFooter implements View.OnClickListener,
+        FgsManagerController.OnDialogDismissedListener,
+        FgsManagerController.OnNumberOfPackagesChangedListener {
 
     private final View mRootView;
     private final TextView mFooterText;
     private final Context mContext;
     private final Executor mMainExecutor;
     private final Executor mExecutor;
-    private final RunningFgsController mRunningFgsController;
-    private final FgsManagerDialogFactory mFgsManagerDialogFactory;
+
+    private final FgsManagerController mFgsManagerController;
 
     private boolean mIsInitialized = false;
-    private boolean mIsAvailable = false;
+    private int mNumPackages;
 
     @Inject
     QSFgsManagerFooter(@Named(QS_FGS_MANAGER_FOOTER_VIEW) View rootView,
-            @Main Executor mainExecutor, RunningFgsController runningFgsController,
-            @Background Executor executor,
-            FgsManagerDialogFactory fgsManagerDialogFactory) {
+            @Main Executor mainExecutor, @Background Executor executor,
+            FgsManagerController fgsManagerController) {
         mRootView = rootView;
         mFooterText = mRootView.findViewById(R.id.footer_text);
         ImageView icon = mRootView.findViewById(R.id.primary_footer_icon);
@@ -66,8 +61,7 @@
         mContext = rootView.getContext();
         mMainExecutor = mainExecutor;
         mExecutor = executor;
-        mRunningFgsController = runningFgsController;
-        mFgsManagerDialogFactory = fgsManagerDialogFactory;
+        mFgsManagerController = fgsManagerController;
     }
 
     public void init() {
@@ -75,22 +69,28 @@
             return;
         }
 
+        mFgsManagerController.init();
+
         mRootView.setOnClickListener(this);
 
-        mRunningFgsController.addCallback(packages -> refreshState());
-
-        DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI, mExecutor,
-                (DeviceConfig.OnPropertiesChangedListener) properties -> {
-                    mIsAvailable = properties.getBoolean(TASK_MANAGER_ENABLED, mIsAvailable);
-                });
-        mIsAvailable = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, TASK_MANAGER_ENABLED, false);
-
         mIsInitialized = true;
     }
 
+    public void setListening(boolean listening) {
+        if (listening) {
+            mFgsManagerController.addOnDialogDismissedListener(this);
+            mFgsManagerController.addOnNumberOfPackagesChangedListener(this);
+            mNumPackages = mFgsManagerController.getNumRunningPackages();
+            refreshState();
+        } else {
+            mFgsManagerController.removeOnDialogDismissedListener(this);
+            mFgsManagerController.removeOnNumberOfPackagesChangedListener(this);
+        }
+    }
+
     @Override
     public void onClick(View view) {
-        mFgsManagerDialogFactory.create(mRootView);
+        mFgsManagerController.showDialog(mRootView);
     }
 
     public void refreshState() {
@@ -101,17 +101,25 @@
         return mRootView;
     }
 
-    private boolean isAvailable() {
-        return mIsAvailable;
-    }
-
     public void handleRefreshState() {
-        int numPackages = mRunningFgsController.getPackagesWithFgs().size();
         mMainExecutor.execute(() -> {
             mFooterText.setText(mContext.getResources().getQuantityString(
-                    R.plurals.fgs_manager_footer_label, numPackages, numPackages));
-            mRootView.setVisibility(numPackages > 0 && isAvailable() ? View.VISIBLE : View.GONE);
+                    R.plurals.fgs_manager_footer_label, mNumPackages, mNumPackages));
+            if (mFgsManagerController.shouldUpdateFooterVisibility()) {
+                mRootView.setVisibility(mNumPackages > 0
+                        && mFgsManagerController.isAvailable() ? View.VISIBLE : View.GONE);
+            }
         });
     }
 
+    @Override
+    public void onDialogDismissed() {
+        refreshState();
+    }
+
+    @Override
+    public void onNumberOfPackagesChanged(int numPackages) {
+        mNumPackages = numPackages;
+        refreshState();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
index 9f585bd..7cf63f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHost.java
@@ -19,7 +19,6 @@
 import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.qs.external.TileServices;
 
 import java.util.Collection;
 
@@ -35,7 +34,6 @@
     Collection<QSTile> getTiles();
     void addCallback(Callback callback);
     void removeCallback(Callback callback);
-    TileServices getTileServices();
     void removeTile(String tileSpec);
     void removeTiles(Collection<String> specs);
     void unmarkTileAsAutoAdded(String tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index cbfe944..8f268b5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -192,6 +192,7 @@
             refreshAllTiles();
         }
 
+        mQSFgsManagerFooter.setListening(listening);
         mQsSecurityFooter.setListening(listening);
 
         // Set the listening as soon as the QS fragment starts listening regardless of the
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index cca4913..c693075 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -24,7 +24,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings.Secure;
-import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
@@ -50,7 +49,6 @@
 import com.android.systemui.qs.external.TileLifecycleManager;
 import com.android.systemui.qs.external.TileServiceKey;
 import com.android.systemui.qs.external.TileServiceRequestController;
-import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.plugins.PluginManager;
@@ -89,7 +87,6 @@
     private final Context mContext;
     private final LinkedHashMap<String, QSTile> mTiles = new LinkedHashMap<>();
     protected final ArrayList<String> mTileSpecs = new ArrayList<>();
-    private final TileServices mServices;
     private final TunerService mTunerService;
     private final PluginManager mPluginManager;
     private final DumpManager mDumpManager;
@@ -111,6 +108,7 @@
     private SecureSettings mSecureSettings;
 
     private final TileServiceRequestController mTileServiceRequestController;
+    private TileLifecycleManager.Factory mTileLifeCycleManagerFactory;
 
     @Inject
     public QSTileHost(Context context,
@@ -129,7 +127,8 @@
             UserTracker userTracker,
             SecureSettings secureSettings,
             CustomTileStatePersister customTileStatePersister,
-            TileServiceRequestController.Builder tileServiceRequestControllerBuilder
+            TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
+            TileLifecycleManager.Factory tileLifecycleManagerFactory
     ) {
         mIconController = iconController;
         mContext = context;
@@ -141,9 +140,9 @@
         mUiEventLogger = uiEventLogger;
         mBroadcastDispatcher = broadcastDispatcher;
         mTileServiceRequestController = tileServiceRequestControllerBuilder.create(this);
+        mTileLifeCycleManagerFactory = tileLifecycleManagerFactory;
 
         mInstanceIdSequence = new InstanceIdSequence(MAX_QS_INSTANCE_ID);
-        mServices = new TileServices(this, bgLooper, mBroadcastDispatcher, userTracker);
         mStatusBarOptional = statusBarOptional;
 
         mQsFactories.add(defaultFactory);
@@ -177,7 +176,6 @@
         mTiles.values().forEach(tile -> tile.destroy());
         mAutoTiles.destroy();
         mTunerService.removeTunable(this);
-        mServices.destroy();
         mPluginManager.removePluginListener(this);
         mDumpManager.unregisterDumpable(TAG);
         mTileServiceRequestController.destroy();
@@ -257,11 +255,6 @@
         return mCurrentUser;
     }
 
-    @Override
-    public TileServices getTileServices() {
-        return mServices;
-    }
-
     public int indexOf(String spec) {
         return mTileSpecs.indexOf(spec);
     }
@@ -460,10 +453,8 @@
             if (!newTiles.contains(tileSpec)) {
                 ComponentName component = CustomTile.getComponentFromSpec(tileSpec);
                 Intent intent = new Intent().setComponent(component);
-                TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
-                        mContext, mServices, new Tile(), intent,
-                        new UserHandle(mCurrentUser),
-                        mBroadcastDispatcher);
+                TileLifecycleManager lifecycleManager = mTileLifeCycleManagerFactory.create(
+                        intent, new UserHandle(mCurrentUser));
                 lifecycleManager.onStopListening();
                 lifecycleManager.onTileRemoved();
                 mCustomTileStatePersister.removeState(new TileServiceKey(component, mCurrentUser));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 2d2fa1f..a3af0e5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -17,12 +17,16 @@
 package com.android.systemui.qs;
 
 import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
+import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_COLLAPSED_LANDSCAPE_MEDIA;
 import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaFlags;
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.qs.QSTile;
@@ -31,6 +35,7 @@
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
+import com.android.systemui.util.leak.RotationUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -54,11 +59,16 @@
     private final QuickQSBrightnessController mBrightnessController;
     private final BrightnessMirrorHandler mBrightnessMirrorHandler;
 
+    private final MediaFlags mMediaFlags;
+    private final boolean mUsingCollapsedLandscapeMedia;
+
     @Inject
     QuickQSPanelController(QuickQSPanel view, QSTileHost qsTileHost,
             QSCustomizerController qsCustomizerController,
             @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
             @Named(QUICK_QS_PANEL) MediaHost mediaHost,
+            @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA) boolean usingCollapsedLandscapeMedia,
+            MediaFlags mediaFlags,
             MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
             DumpManager dumpManager,
             QuickQSBrightnessController quickQSBrightnessController
@@ -67,17 +77,36 @@
                 uiEventLogger, qsLogger, dumpManager);
         mBrightnessController = quickQSBrightnessController;
         mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
+        mUsingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia;
+        mMediaFlags = mediaFlags;
     }
 
     @Override
     protected void onInit() {
         super.onInit();
-        mMediaHost.setExpansion(0.0f);
+        updateMediaExpansion();
         mMediaHost.setShowsOnlyActiveMedia(true);
         mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
         mBrightnessController.init(mShouldUseSplitNotificationShade);
     }
 
+    private void updateMediaExpansion() {
+        int rotation = getRotation();
+        boolean isLandscape = rotation == RotationUtils.ROTATION_LANDSCAPE
+                || rotation == RotationUtils.ROTATION_SEASCAPE;
+        if (mMediaFlags.useMediaSessionLayout()
+                && (!mUsingCollapsedLandscapeMedia || !isLandscape)) {
+            mMediaHost.setExpansion(MediaHost.EXPANDED);
+        } else {
+            mMediaHost.setExpansion(MediaHost.COLLAPSED);
+        }
+    }
+
+    @VisibleForTesting
+    protected int getRotation() {
+        return RotationUtils.getRotation(getContext());
+    }
+
     @Override
     protected void onViewAttached() {
         super.onViewAttached();
@@ -116,6 +145,7 @@
     @Override
     protected void onConfigurationChanged() {
         mBrightnessController.refreshVisibility(mShouldUseSplitNotificationShade);
+        updateMediaExpansion();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 776ee10..fdf9ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.dagger;
 
+import static com.android.systemui.util.Utils.useCollapsedMediaInLandscape;
 import static com.android.systemui.util.Utils.useQsMediaPlayer;
 
 import android.content.Context;
@@ -56,6 +57,7 @@
     String QS_FGS_MANAGER_FOOTER_VIEW = "qs_fgs_manager_footer";
     String QS_SECURITY_FOOTER_VIEW = "qs_security_footer";
     String QS_USING_MEDIA_PLAYER = "qs_using_media_player";
+    String QS_USING_COLLAPSED_LANDSCAPE_MEDIA = "qs_using_collapsed_landscape_media";
 
     /**
      * Provide a context themed using the QS theme
@@ -173,6 +175,13 @@
 
     /** */
     @Provides
+    @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA)
+    static boolean providesQSUsingCollapsedLandscapeMedia(Context context) {
+        return useCollapsedMediaInLandscape(context.getResources());
+    }
+
+    /** */
+    @Provides
     @QSScope
     static OngoingPrivacyChip providesPrivacyChip(QuickStatusBarHeader qsHeader) {
         return qsHeader.findViewById(R.id.privacy_chip);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 48255b5..5d4b3da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -28,14 +28,13 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.qs.ReduceBrightColorsController;
+import com.android.systemui.qs.external.QSExternalModule;
 import com.android.systemui.statusbar.phone.AutoTileManager;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.DeviceControlsController;
 import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.RunningFgsController;
-import com.android.systemui.statusbar.policy.RunningFgsControllerImpl;
 import com.android.systemui.statusbar.policy.WalletController;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -49,7 +48,7 @@
  * Module for QS dependencies
  */
 @Module(subcomponents = {QSFragmentComponent.class},
-        includes = {MediaModule.class, QSFlagsModule.class})
+        includes = {MediaModule.class, QSExternalModule.class, QSFlagsModule.class})
 public interface QSModule {
 
     @Provides
@@ -91,9 +90,4 @@
     /** */
     @Binds
     QSHost provideQsHost(QSTileHost controllerImpl);
-
-    /** */
-    @Binds
-    RunningFgsController provideRunningFgsController(
-            RunningFgsControllerImpl runningFgsController);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 4f15351..c4386ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -51,7 +51,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -103,6 +102,7 @@
     private final TileServiceKey mKey;
 
     private final AtomicBoolean mInitialDefaultIconFetched = new AtomicBoolean(false);
+    private final TileServices mTileServices;
 
     private CustomTile(
             QSHost host,
@@ -115,10 +115,12 @@
             QSLogger qsLogger,
             String action,
             Context userContext,
-            CustomTileStatePersister customTileStatePersister
+            CustomTileStatePersister customTileStatePersister,
+            TileServices tileServices
     ) {
         super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
+        mTileServices = tileServices;
         mWindowManager = WindowManagerGlobal.getWindowManagerService();
         mComponent = ComponentName.unflattenFromString(action);
         mTile = new Tile();
@@ -126,7 +128,7 @@
         mUser = mUserContext.getUserId();
         mKey = new TileServiceKey(mComponent, mUser);
 
-        mServiceManager = host.getTileServices().getTileWrapper(this);
+        mServiceManager = tileServices.getTileWrapper(this);
         mService = mServiceManager.getTileService();
         mCustomTileStatePersister = customTileStatePersister;
     }
@@ -349,7 +351,7 @@
             } catch (RemoteException e) {
             }
         }
-        mHost.getTileServices().freeService(this, mServiceManager);
+        mTileServices.freeService(this, mServiceManager);
     }
 
     @Override
@@ -473,7 +475,7 @@
     }
 
     public void startUnlockAndRun() {
-        Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
+        mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
             try {
                 mService.onUnlockComplete();
             } catch (RemoteException e) {
@@ -529,6 +531,7 @@
         final ActivityStarter mActivityStarter;
         final QSLogger mQSLogger;
         final CustomTileStatePersister mCustomTileStatePersister;
+        private TileServices mTileServices;
 
         Context mUserContext;
         String mSpec = "";
@@ -543,7 +546,8 @@
                 StatusBarStateController statusBarStateController,
                 ActivityStarter activityStarter,
                 QSLogger qsLogger,
-                CustomTileStatePersister customTileStatePersister
+                CustomTileStatePersister customTileStatePersister,
+                TileServices tileServices
         ) {
             mQSHostLazy = hostLazy;
             mBackgroundLooper = backgroundLooper;
@@ -554,6 +558,7 @@
             mActivityStarter = activityStarter;
             mQSLogger = qsLogger;
             mCustomTileStatePersister = customTileStatePersister;
+            mTileServices = tileServices;
         }
 
         Builder setSpec(@NonNull String spec) {
@@ -583,7 +588,8 @@
                     mQSLogger,
                     action,
                     mUserContext,
-                    mCustomTileStatePersister
+                    mCustomTileStatePersister,
+                    mTileServices
             );
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/PackageManagerAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/external/PackageManagerAdapter.java
index ffe66f4..6cf4441 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/PackageManagerAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/PackageManagerAdapter.java
@@ -26,6 +26,8 @@
 import android.content.pm.ServiceInfo;
 import android.os.RemoteException;
 
+import javax.inject.Inject;
+
 // Adapter that wraps calls to PackageManager or IPackageManager for {@link TileLifecycleManager}.
 // TODO: This is very much an intermediate step to allow for PackageManager mocking and should be
 // abstracted into something more useful for other tests in systemui.
@@ -37,6 +39,7 @@
 
     // Uses the PackageManager for the provided context.
     // When necessary, uses the IPackagemanger in AppGlobals.
+    @Inject
     public PackageManagerAdapter(Context context) {
         mPackageManager = context.getPackageManager();
         mIPackageManager = AppGlobals.getPackageManager();
diff --git a/services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSExternalModule.kt
similarity index 71%
rename from services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java
rename to packages/SystemUI/src/com/android/systemui/qs/external/QSExternalModule.kt
index 3c99a98..f7db80b 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/TestDreamService.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSExternalModule.kt
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.server.dreams;
+package com.android.systemui.qs.external
 
-import android.service.dreams.DreamService;
+import android.service.quicksettings.IQSService
+import dagger.Binds
+import dagger.Module
 
-/**
- * Dream service implementation for unit testing.
- */
-public class TestDreamService extends DreamService {
-}
+@Module
+interface QSExternalModule {
+    @Binds
+    fun bindsIQSService(impl: TileServices): IQSService
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 17ae7ff..32e0805 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -31,21 +31,24 @@
 import android.os.UserHandle;
 import android.service.quicksettings.IQSService;
 import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
 import android.util.ArraySet;
 import android.util.Log;
 
 import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
 
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
 
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
 /**
  * Manages the lifecycle of a TileService.
  * <p>
@@ -102,16 +105,10 @@
     // Return value from bindServiceAsUser, determines whether safe to call unbind.
     private boolean mIsBound;
 
-    public TileLifecycleManager(Handler handler, Context context, IQSService service, Tile tile,
-            Intent intent, UserHandle user, BroadcastDispatcher broadcastDispatcher) {
-        this(handler, context, service, tile, intent, user, new PackageManagerAdapter(context),
-                broadcastDispatcher);
-    }
-
-    @VisibleForTesting
-    TileLifecycleManager(Handler handler, Context context, IQSService service, Tile tile,
-            Intent intent, UserHandle user, PackageManagerAdapter packageManagerAdapter,
-            BroadcastDispatcher broadcastDispatcher) {
+    @AssistedInject
+    TileLifecycleManager(@Main Handler handler, Context context, IQSService service,
+            PackageManagerAdapter packageManagerAdapter, BroadcastDispatcher broadcastDispatcher,
+            @Assisted Intent intent, @Assisted UserHandle user) {
         mContext = context;
         mHandler = handler;
         mIntent = intent;
@@ -123,6 +120,13 @@
         if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
     }
 
+    /** Injectable factory for TileLifecycleManager. */
+    @AssistedFactory
+    public interface Factory {
+        /** */
+        TileLifecycleManager create(Intent intent, UserHandle userHandle);
+    }
+
     public ComponentName getComponent() {
         return mIntent.getComponent();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index fda755b..bf565a8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -26,7 +26,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
 import android.util.Log;
 
@@ -73,10 +72,11 @@
     private boolean mStarted = false;
 
     TileServiceManager(TileServices tileServices, Handler handler, ComponentName component,
-            Tile tile, BroadcastDispatcher broadcastDispatcher, UserTracker userTracker) {
+            BroadcastDispatcher broadcastDispatcher, UserTracker userTracker) {
         this(tileServices, handler, userTracker, new TileLifecycleManager(handler,
-                tileServices.getContext(), tileServices, tile, new Intent().setComponent(component),
-                userTracker.getUserHandle(), broadcastDispatcher));
+                tileServices.getContext(), tileServices,
+                new PackageManagerAdapter(tileServices.getContext()), broadcastDispatcher,
+                new Intent().setComponent(component), userTracker.getUserHandle()));
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index 0a3c17c..32515a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -38,8 +38,8 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.Dependency;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -50,6 +50,8 @@
 import java.util.Comparator;
 import java.util.Objects;
 
+import javax.inject.Inject;
+
 /**
  * Runs the day-to-day operations of which tiles should be bound and when.
  */
@@ -65,14 +67,21 @@
     private final Handler mHandler;
     private final Handler mMainHandler;
     private final QSTileHost mHost;
+    private final KeyguardStateController mKeyguardStateController;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final UserTracker mUserTracker;
 
     private int mMaxBound = DEFAULT_MAX_BOUND;
 
-    public TileServices(QSTileHost host, Looper looper, BroadcastDispatcher broadcastDispatcher,
-            UserTracker userTracker) {
+    @Inject
+    public TileServices(
+            QSTileHost host,
+            @Main Looper looper,
+            BroadcastDispatcher broadcastDispatcher,
+            UserTracker userTracker,
+            KeyguardStateController keyguardStateController) {
         mHost = host;
+        mKeyguardStateController = keyguardStateController;
         mContext = mHost.getContext();
         mBroadcastDispatcher = broadcastDispatcher;
         mHandler = new Handler(looper);
@@ -96,8 +105,7 @@
 
     public TileServiceManager getTileWrapper(CustomTile tile) {
         ComponentName component = tile.getComponent();
-        TileServiceManager service = onCreateTileService(component, tile.getQsTile(),
-                mBroadcastDispatcher);
+        TileServiceManager service = onCreateTileService(component, mBroadcastDispatcher);
         synchronized (mServices) {
             mServices.put(tile, service);
             mTiles.put(component, tile);
@@ -108,9 +116,9 @@
         return service;
     }
 
-    protected TileServiceManager onCreateTileService(ComponentName component, Tile tile,
+    protected TileServiceManager onCreateTileService(ComponentName component,
             BroadcastDispatcher broadcastDispatcher) {
-        return new TileServiceManager(this, mHandler, component, tile,
+        return new TileServiceManager(this, mHandler, component,
                 broadcastDispatcher, mUserTracker);
     }
 
@@ -321,16 +329,12 @@
 
     @Override
     public boolean isLocked() {
-        KeyguardStateController keyguardStateController =
-                Dependency.get(KeyguardStateController.class);
-        return keyguardStateController.isShowing();
+        return mKeyguardStateController.isShowing();
     }
 
     @Override
     public boolean isSecure() {
-        KeyguardStateController keyguardStateController =
-                Dependency.get(KeyguardStateController.class);
-        return keyguardStateController.isMethodSecure() && keyguardStateController.isShowing();
+        return mKeyguardStateController.isMethodSecure() && mKeyguardStateController.isShowing();
     }
 
     @Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 821dfa5f..a712ce2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -25,6 +25,7 @@
 import android.content.res.Resources.ID_NULL
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.RippleDrawable
+import android.os.Trace
 import android.service.quicksettings.Tile
 import android.text.TextUtils
 import android.util.Log
@@ -163,6 +164,12 @@
         updateResources()
     }
 
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        Trace.traceBegin(Trace.TRACE_TAG_APP, "QSTileViewImpl#onMeasure")
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        Trace.endSection()
+    }
+
     override fun resetOverride() {
         heightOverride = HeightOverrideable.NO_OVERRIDE
         updateHeight()
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 77c61a4..597f7b7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -112,8 +112,6 @@
             final Optional<StatusBar> statusBarOptional = mStatusBarOptionalLazy.get();
             if (statusBarOptional.map(StatusBar::isKeyguardShowing).orElse(false)) {
                 statusBarOptional.get().executeRunnableDismissingKeyguard(() -> {
-                        // Flush trustmanager before checking device locked per user
-                        mTrustManager.reportKeyguardShowingChanged();
                         mHandler.post(toggleRecents);
                     }, null,  true /* dismissShade */, false /* afterKeyguardGone */,
                     true /* deferred */);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 00a3149..6b251b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -26,6 +26,7 @@
 
 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_BACK_ANIMATION;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
@@ -104,6 +105,7 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
 import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.wm.shell.back.BackAnimation;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.pip.Pip;
@@ -163,6 +165,7 @@
     private final Optional<StartingSurface> mStartingSurface;
     private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController;
     private final Optional<RecentTasks> mRecentTasks;
+    private final Optional<BackAnimation> mBackAnimation;
     private final UiEventLogger mUiEventLogger;
 
     private Region mActiveNavBarRegion;
@@ -508,6 +511,9 @@
             mRecentTasks.ifPresent(recentTasks -> params.putBinder(
                     KEY_EXTRA_RECENT_TASKS,
                     recentTasks.createExternalInterface().asBinder()));
+            mBackAnimation.ifPresent((backAnimation) -> params.putBinder(
+                    KEY_EXTRA_SHELL_BACK_ANIMATION,
+                    backAnimation.createExternalInterface().asBinder()));
 
             try {
                 mOverviewProxy.onInitialize(params);
@@ -566,6 +572,7 @@
             Optional<SplitScreen> splitScreenOptional,
             Optional<OneHanded> oneHandedOptional,
             Optional<RecentTasks> recentTasks,
+            Optional<BackAnimation> backAnimation,
             Optional<StartingSurface> startingSurface,
             BroadcastDispatcher broadcastDispatcher,
             ShellTransitions shellTransitions,
@@ -593,6 +600,7 @@
         mOneHandedOptional = oneHandedOptional;
         mShellTransitions = shellTransitions;
         mRecentTasks = recentTasks;
+        mBackAnimation = backAnimation;
         mUiEventLogger = uiEventLogger;
 
         // Assumes device always starts with back button until launcher tells it that it does not
@@ -677,7 +685,7 @@
         }
 
         if (navBarFragment != null) {
-            navBarFragment.updateSystemUiStateFlags(-1);
+            navBarFragment.updateSystemUiStateFlags();
         }
         if (navBarView != null) {
             navBarView.updateDisabledSystemUiStateFlags();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 5302188..4a7606c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -22,6 +22,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.app.ActivityManager;
 import android.app.Notification;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -33,7 +34,6 @@
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.os.Parcelable;
@@ -57,6 +57,7 @@
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.util.drawable.DrawableSize;
 
 import java.text.NumberFormat;
 import java.util.Arrays;
@@ -84,16 +85,6 @@
     public static final int STATE_DOT = 1;
     public static final int STATE_HIDDEN = 2;
 
-    /**
-     * Maximum allowed byte count for an icon bitmap
-     * @see android.graphics.RecordingCanvas.MAX_BITMAP_SIZE
-     */
-    private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
-    /**
-     * Maximum allowed width or height for an icon drawable, if we can't get byte count
-     */
-    private static final int MAX_IMAGE_SIZE = 5000;
-
     private static final String TAG = "StatusBarIconView";
     private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
             = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
@@ -390,21 +381,6 @@
             return false;
         }
 
-        if (drawable instanceof BitmapDrawable && ((BitmapDrawable) drawable).getBitmap() != null) {
-            // If it's a bitmap we can check the size directly
-            int byteCount = ((BitmapDrawable) drawable).getBitmap().getByteCount();
-            if (byteCount > MAX_BITMAP_SIZE) {
-                Log.w(TAG, "Drawable is too large (" + byteCount + " bytes) " + mIcon);
-                return false;
-            }
-        } else if (drawable.getIntrinsicWidth() > MAX_IMAGE_SIZE
-                || drawable.getIntrinsicHeight() > MAX_IMAGE_SIZE) {
-            // Otherwise, check dimensions
-            Log.w(TAG, "Drawable is too large (" + drawable.getIntrinsicWidth() + "x"
-                    + drawable.getIntrinsicHeight() + ") " + mIcon);
-            return false;
-        }
-
         if (withClear) {
             setImageDrawable(null);
         }
@@ -432,7 +408,7 @@
      * @return Drawable for this item, or null if the package or item could not
      *         be found
      */
-    public static Drawable getIcon(Context sysuiContext,
+    private Drawable getIcon(Context sysuiContext,
             Context context, StatusBarIcon statusBarIcon) {
         int userId = statusBarIcon.user.getIdentifier();
         if (userId == UserHandle.USER_ALL) {
@@ -446,6 +422,16 @@
                 typedValue, true);
         float scaleFactor = typedValue.getFloat();
 
+        // We downscale the loaded drawable to reasonable size to protect against applications
+        // using too much memory. The size can be tweaked in config.xml. Drawables
+        // that are already sized properly won't be touched.
+        boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
+        Resources res = sysuiContext.getResources();
+        int maxIconSize = res.getDimensionPixelSize(isLowRamDevice
+                                ? com.android.internal.R.dimen.notification_small_icon_size_low_ram
+                                : com.android.internal.R.dimen.notification_small_icon_size);
+        icon = DrawableSize.downscaleToSize(res, icon, maxIconSize, maxIconSize);
+
         // No need to scale the icon, so return it as is.
         if (scaleFactor == 1.f) {
             return icon;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt
index 8dc01f0..236129f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/DwellRippleShader.kt
@@ -33,7 +33,7 @@
  *
  * Modeled after frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java.
  */
-class DwellRippleShader internal constructor() : RuntimeShader(SHADER, false) {
+class DwellRippleShader internal constructor() : RuntimeShader(SHADER) {
     companion object {
         private const val SHADER_UNIFORMS = """uniform vec2 in_origin;
                 uniform float in_time;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt
index 22fbf91..bdad36c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt
@@ -28,7 +28,7 @@
  *
  * Modeled after frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java.
  */
-class RippleShader internal constructor() : RuntimeShader(SHADER, false) {
+class RippleShader internal constructor() : RuntimeShader(SHADER) {
     companion object {
         private const val SHADER_UNIFORMS = """uniform vec2 in_origin;
                 uniform float in_progress;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt
new file mode 100644
index 0000000..6f8e5da
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection
+
+import android.view.Choreographer
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.util.ListenerSet
+import com.android.systemui.util.concurrency.DelayableExecutor
+import dagger.Module
+import dagger.Provides
+
+/**
+ * Choreographs evaluation resulting from multiple asynchronous sources. Specifically, it exposes
+ * [schedule], and [addOnEvalListener]; the former will "schedule" an asynchronous invocation of the
+ * latter. Multiple invocations of [schedule] before any added listeners are invoked have no effect.
+ */
+interface NotifPipelineChoreographer {
+    /**
+     * Schedules all listeners registered with [addOnEvalListener] to be asynchronously executed at
+     * some point in the future. The exact timing is up to the implementation.
+     */
+    fun schedule()
+
+    /** Cancels a pending evaluation triggered by any recent calls to [schedule]. */
+    fun cancel()
+
+    /** Adds a listener [Runnable] that will be invoked when the scheduled evaluation occurs. */
+    fun addOnEvalListener(onEvalListener: Runnable)
+
+    /** Removes a listener previously registered with [addOnEvalListener]. */
+    fun removeOnEvalListener(onEvalListener: Runnable)
+}
+
+@Module
+object NotifPipelineChoreographerModule {
+    @Provides
+    @JvmStatic
+    @SysUISingleton
+    fun provideChoreographer(
+        choreographer: Choreographer,
+        @Main mainExecutor: DelayableExecutor
+    ): NotifPipelineChoreographer = NotifPipelineChoreographerImpl(choreographer, mainExecutor)
+}
+
+private const val TIMEOUT_MS: Long = 100
+
+private class NotifPipelineChoreographerImpl(
+    private val viewChoreographer: Choreographer,
+    private val executor: DelayableExecutor
+) : NotifPipelineChoreographer {
+
+    private val listeners = ListenerSet<Runnable>()
+    private var timeoutSubscription: Runnable? = null
+    private var isScheduled = false
+
+    private val frameCallback = Choreographer.FrameCallback {
+        if (isScheduled) {
+            isScheduled = false
+            timeoutSubscription?.run()
+            listeners.forEach { it.run() }
+        }
+    }
+
+    override fun schedule() {
+        if (isScheduled) return
+        isScheduled = true
+        viewChoreographer.postFrameCallback(frameCallback)
+        if (!isScheduled) {
+            // Guard against synchronous evaluation of the frame callback.
+            return
+        }
+        timeoutSubscription = executor.executeDelayed(::onTimeout, TIMEOUT_MS)
+    }
+
+    override fun cancel() {
+        if (!isScheduled) return
+        timeoutSubscription?.run()
+        viewChoreographer.removeFrameCallback(frameCallback)
+    }
+
+    override fun addOnEvalListener(onEvalListener: Runnable) {
+        listeners.addIfAbsent(onEvalListener)
+    }
+
+    override fun removeOnEvalListener(onEvalListener: Runnable) {
+        listeners.remove(onEvalListener)
+    }
+
+    private fun onTimeout() {
+        if (isScheduled) {
+            isScheduled = false
+            viewChoreographer.removeFrameCallback(frameCallback)
+            listeners.forEach { it.run() }
+        }
+    }
+}
+
+class FakeNotifPipelineChoreographer : NotifPipelineChoreographer {
+
+    var isScheduled = false
+    val listeners = ListenerSet<Runnable>()
+
+    fun runIfScheduled() {
+        if (isScheduled) {
+            isScheduled = false
+            listeners.forEach { it.run() }
+        }
+    }
+
+    override fun schedule() {
+        isScheduled = true
+    }
+
+    override fun cancel() {
+        isScheduled = false
+    }
+
+    override fun addOnEvalListener(onEvalListener: Runnable) {
+        listeners.addIfAbsent(onEvalListener)
+    }
+
+    override fun removeOnEvalListener(onEvalListener: Runnable) {
+        listeners.remove(onEvalListener)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 31d9f09..e0c2fd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -122,20 +122,23 @@
 
     private List<ListEntry> mReadOnlyNotifList = Collections.unmodifiableList(mNotifList);
     private List<ListEntry> mReadOnlyNewNotifList = Collections.unmodifiableList(mNewNotifList);
+    private final NotifPipelineChoreographer mChoreographer;
 
     @Inject
     public ShadeListBuilder(
-            SystemClock systemClock,
-            NotifPipelineFlags flags,
-            ShadeListBuilderLogger logger,
             DumpManager dumpManager,
-            NotificationInteractionTracker interactionTracker
+            NotifPipelineChoreographer pipelineChoreographer,
+            NotifPipelineFlags flags,
+            NotificationInteractionTracker interactionTracker,
+            ShadeListBuilderLogger logger,
+            SystemClock systemClock
     ) {
         Assert.isMainThread();
         mSystemClock = systemClock;
         mLogger = logger;
         mAlwaysLogList = flags.isDevLoggingEnabled();
         mInteractionTracker = interactionTracker;
+        mChoreographer = pipelineChoreographer;
         dumpManager.registerDumpable(TAG, this);
 
         setSectioners(Collections.emptyList());
@@ -148,6 +151,7 @@
     public void attach(NotifCollection collection) {
         Assert.isMainThread();
         collection.setBuildListener(mReadyForBuildListener);
+        mChoreographer.addOnEvalListener(this::buildList);
     }
 
     /**
@@ -226,8 +230,13 @@
 
         mNotifSections.clear();
         for (NotifSectioner sectioner : sectioners) {
-            mNotifSections.add(new NotifSection(sectioner, mNotifSections.size()));
+            final NotifSection section = new NotifSection(sectioner, mNotifSections.size());
+            final NotifComparator sectionComparator = section.getComparator();
+            mNotifSections.add(section);
             sectioner.setInvalidationListener(this::onNotifSectionInvalidated);
+            if (sectionComparator != null) {
+                sectionComparator.setInvalidationListener(this::onNotifComparatorInvalidated);
+            }
         }
 
         mNotifSections.add(new NotifSection(DEFAULT_SECTIONER, mNotifSections.size()));
@@ -285,7 +294,7 @@
 
                     mLogger.logOnBuildList();
                     mAllEntries = entries;
-                    buildList();
+                    mChoreographer.schedule();
                 }
             };
 
@@ -1098,7 +1107,12 @@
         callOnCleanup(mNotifComparators);
 
         for (int i = 0; i < mNotifSections.size(); i++) {
-            mNotifSections.get(i).getSectioner().onCleanup();
+            final NotifSection notifSection = mNotifSections.get(i);
+            notifSection.getSectioner().onCleanup();
+            final NotifComparator comparator = notifSection.getComparator();
+            if (comparator != null) {
+                comparator.onCleanup();
+            }
         }
 
         callOnCleanup(List.of(getStabilityManager()));
@@ -1111,6 +1125,19 @@
         }
     }
 
+    @Nullable
+    private NotifComparator getSectionComparator(
+            @NonNull ListEntry o1, @NonNull ListEntry o2) {
+        final NotifSection section = o1.getSection();
+        if (section != o2.getSection()) {
+            throw new RuntimeException("Entry ordering should only be done within sections");
+        }
+        if (section != null) {
+            return section.getComparator();
+        }
+        return null;
+    }
+
     private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
         int cmp = Integer.compare(
                 o1.getSectionIndex(),
@@ -1122,6 +1149,12 @@
         cmp = Integer.compare(index1, index2);
         if (cmp != 0) return cmp;
 
+        NotifComparator sectionComparator = getSectionComparator(o1, o2);
+        if (sectionComparator != null) {
+            cmp = sectionComparator.compare(o1, o2);
+            if (cmp != 0) return cmp;
+        }
+
         for (int i = 0; i < mNotifComparators.size(); i++) {
             cmp = mNotifComparators.get(i).compare(o1, o2);
             if (cmp != 0) return cmp;
@@ -1252,7 +1285,7 @@
     private void rebuildListIfBefore(@PipelineState.StateName int state) {
         mPipelineState.requireIsBefore(state);
         if (mPipelineState.is(STATE_IDLE)) {
-            buildList();
+            mChoreographer.schedule();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index ba88ad7..a390e9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -51,23 +51,20 @@
     val sectioner = object : NotifSectioner("People", BUCKET_PEOPLE) {
         override fun isInSection(entry: ListEntry): Boolean =
                 isConversation(entry)
+
+        override fun getComparator() = object : NotifComparator("People") {
+            override fun compare(entry1: ListEntry, entry2: ListEntry): Int {
+                val type1 = getPeopleType(entry1)
+                val type2 = getPeopleType(entry2)
+                return type2.compareTo(type1)
+            }
+        }
+
         override fun getHeaderNodeController() =
                 // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and peopleHeaderController
                 if (RankingCoordinator.SHOW_ALL_SECTIONS) peopleHeaderController else null
     }
 
-    val comparator = object : NotifComparator("People") {
-        override fun compare(entry1: ListEntry, entry2: ListEntry): Int {
-            assert(entry1.section === entry2.section)
-            if (entry1.section?.sectioner !== sectioner) {
-                return 0
-            }
-            val type1 = getPeopleType(entry1)
-            val type2 = getPeopleType(entry2)
-            return type2.compareTo(type1)
-        }
-    }
-
     override fun attach(pipeline: NotifPipeline) {
         pipeline.addPromoter(notificationPromoter)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 0311324..41b0706 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
@@ -456,6 +457,13 @@
             // TODO: This check won't notice if a child of the group is going to HUN...
             isGoingToShowHunNoRetract(entry)
 
+        override fun getComparator(): NotifComparator {
+            return object : NotifComparator("HeadsUp") {
+                override fun compare(o1: ListEntry, o2: ListEntry): Int =
+                    mHeadsUpManager.compare(o1.representativeEntry, o2.representativeEntry)
+            }
+        }
+
         override fun getHeaderNodeController(): NodeController? =
             // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mIncomingHeaderController
             if (RankingCoordinator.SHOW_ALL_SECTIONS) mIncomingHeaderController else null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 850cb4b..757fb5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -20,7 +20,6 @@
 import com.android.systemui.statusbar.notification.NotifPipelineFlags
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
 import java.io.FileDescriptor
 import java.io.PrintWriter
@@ -64,7 +63,6 @@
 
     private val mCoordinators: MutableList<Coordinator> = ArrayList()
     private val mOrderedSections: MutableList<NotifSectioner> = ArrayList()
-    private val mOrderedComparators: MutableList<NotifComparator> = ArrayList()
 
     /**
      * Creates all the coordinators.
@@ -119,9 +117,6 @@
         mOrderedSections.add(rankingCoordinator.alertingSectioner) // Alerting
         mOrderedSections.add(rankingCoordinator.silentSectioner) // Silent
         mOrderedSections.add(rankingCoordinator.minimizedSectioner) // Minimized
-
-        // Manually add ordered comparators
-        mOrderedComparators.add(conversationCoordinator.comparator)
     }
 
     /**
@@ -133,7 +128,6 @@
             c.attach(pipeline)
         }
         pipeline.setSections(mOrderedSections)
-        pipeline.setComparators(mOrderedComparators)
     }
 
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
index 8444287..263737e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection.listbuilder
 
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
 import com.android.systemui.statusbar.notification.collection.render.NodeController
 import com.android.systemui.statusbar.notification.stack.PriorityBucket
@@ -29,5 +30,7 @@
 
     val headerController: NodeController? = sectioner.headerNodeController
 
+    val comparator: NotifComparator? = sectioner.comparator
+
     @PriorityBucket val bucket: Int = sectioner.bucket
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
index ef9ee11..8c52c53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
@@ -55,8 +55,22 @@
     public abstract boolean isInSection(ListEntry entry);
 
     /**
+     * Returns an optional {@link NotifComparator} to sort entries only in this section.
+     * {@link ListEntry} instances passed to this comparator are guaranteed to have this section,
+     * and this ordering will take precedence over any global comparators supplied to {@link
+     * com.android.systemui.statusbar.notification.collection.NotifPipeline#setComparators(List)}.
+     *
+     * NOTE: this method is only called once when the Sectioner is attached.
+     */
+    public @Nullable NotifComparator getComparator() {
+        return null;
+    }
+
+    /**
      * Returns an optional {@link NodeSpec} for the section header. If {@code null}, no header will
      * be used for the section.
+     *
+     * NOTE: this method is only called once when the Sectioner is attached.
      */
     public @Nullable NodeController getHeaderNodeController() {
         return null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
index 4de8e7a..b76169f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.collection.render
 
 import android.view.View
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 
@@ -41,6 +42,7 @@
     override fun addChildAt(child: NodeController, index: Int) {
         listContainer.addContainerViewAt(child.view, index)
         listContainer.onNotificationViewUpdateFinished()
+        (child.view as? ExpandableNotificationRow)?.isChangingPosition = false
     }
 
     override fun moveChildTo(child: NodeController, index: Int) {
@@ -50,6 +52,7 @@
     override fun removeChild(child: NodeController, isTransfer: Boolean) {
         if (isTransfer) {
             listContainer.setChildTransferInProgress(true)
+            (child.view as? ExpandableNotificationRow)?.isChangingPosition = true
         }
         listContainer.removeContainerView(child.view)
         if (isTransfer) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 45a9092..35d4582 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -47,6 +47,7 @@
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotifPipelineChoreographerModule;
 import com.android.systemui.statusbar.notification.collection.coordinator.ShadeEventCoordinator;
 import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorsModule;
@@ -103,6 +104,7 @@
  */
 @Module(includes = {
         CoordinatorsModule.class,
+        NotifPipelineChoreographerModule.class,
         NotifPanelEventSourceModule.class,
         NotificationSectionHeadersModule.class,
 })
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 46efef6..c4beb5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -27,8 +27,9 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -89,6 +90,7 @@
     private final OnUserInteractionCallback mOnUserInteractionCallback;
     private final FalsingManager mFalsingManager;
     private final FalsingCollector mFalsingCollector;
+    private final FeatureFlags mFeatureFlags;
     private final boolean mAllowLongPress;
     private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
     private final Optional<BubblesManager> mBubblesManagerOptional;
@@ -119,6 +121,7 @@
             OnUserInteractionCallback onUserInteractionCallback,
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
+            FeatureFlags featureFlags,
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             Optional<BubblesManager> bubblesManagerOptional,
             ExpandableNotificationRowDragController dragController) {
@@ -145,6 +148,7 @@
         mOnFeedbackClickListener = mNotificationGutsManager::openGuts;
         mAllowLongPress = allowLongPress;
         mFalsingCollector = falsingCollector;
+        mFeatureFlags = featureFlags;
         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
         mBubblesManagerOptional = bubblesManagerOptional;
         mDragController = dragController;
@@ -179,7 +183,7 @@
         );
         mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
         if (mAllowLongPress) {
-            if (mView.getResources().getBoolean(R.bool.config_notificationToContents)) {
+            if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_DRAG_TO_CONTENTS)) {
                 mView.setDragController(mDragController);
             }
 
@@ -248,19 +252,25 @@
 
         mView.addChildNotification((ExpandableNotificationRow) child.getView(), index);
         mListContainer.notifyGroupChildAdded(childView);
+        childView.setChangingPosition(false);
     }
 
     @Override
     public void moveChildTo(NodeController child, int index) {
         ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView();
+        childView.setChangingPosition(true);
         mView.removeChildNotification(childView);
         mView.addChildNotification(childView, index);
+        childView.setChangingPosition(false);
     }
 
     @Override
     public void removeChild(NodeController child, boolean isTransfer) {
         ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView();
 
+        if (isTransfer) {
+            childView.setChangingPosition(true);
+        }
         mView.removeChildNotification(childView);
         if (!isTransfer) {
             mListContainer.notifyGroupChildRemoved(childView, mView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 0b6d759..7d035a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -35,6 +35,10 @@
     private FooterViewButton mClearAllButton;
     private FooterViewButton mManageButton;
     private boolean mShowHistory;
+    // String cache, for performance reasons.
+    // Reading them from a Resources object can be quite slow sometimes.
+    private String mManageNotificationText;
+    private String mManageNotificationHistoryText;
 
     public FooterView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -68,6 +72,8 @@
         super.onFinishInflate();
         mClearAllButton = (FooterViewButton) findSecondaryView();
         mManageButton = findViewById(R.id.manage_text);
+        updateResources();
+        updateText();
     }
 
     public void setManageButtonClickListener(OnClickListener listener) {
@@ -86,15 +92,20 @@
     }
 
     public void showHistory(boolean showHistory) {
+        if (mShowHistory == showHistory) {
+            return;
+        }
         mShowHistory = showHistory;
+        updateText();
+    }
+
+    private void updateText() {
         if (mShowHistory) {
-            mManageButton.setText(R.string.manage_notifications_history_text);
-            mManageButton.setContentDescription(
-                    mContext.getString(R.string.manage_notifications_history_text));
+            mManageButton.setText(mManageNotificationHistoryText);
+            mManageButton.setContentDescription(mManageNotificationHistoryText);
         } else {
-            mManageButton.setText(R.string.manage_notifications_text);
-            mManageButton.setContentDescription(
-                    mContext.getString(R.string.manage_notifications_text));
+            mManageButton.setText(mManageNotificationText);
+            mManageButton.setContentDescription(mManageNotificationText);
         }
     }
 
@@ -109,7 +120,8 @@
         mClearAllButton.setText(R.string.clear_all_notifications_text);
         mClearAllButton.setContentDescription(
                 mContext.getString(R.string.accessibility_clear_all));
-        showHistory(mShowHistory);
+        updateResources();
+        updateText();
     }
 
     /**
@@ -124,6 +136,12 @@
         mManageButton.setTextColor(textColor);
     }
 
+    private void updateResources() {
+        mManageNotificationText = getContext().getString(R.string.manage_notifications_text);
+        mManageNotificationHistoryText = getContext()
+                .getString(R.string.manage_notifications_history_text);
+    }
+
     @Override
     public ExpandableViewState createExpandableViewState() {
         return new FooterViewState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index ce3e27c..f40a3c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -76,7 +76,10 @@
     private float mHideAmount;
     private boolean mAppearing;
     private float mPulseHeight = MAX_PULSE_HEIGHT;
+
+    /** How we much we are sleeping. 1f fully dozing (AOD), 0f fully awake (for all other states) */
     private float mDozeAmount = 0.0f;
+
     private Runnable mOnPulseHeightChangedListener;
     private ExpandableNotificationRow mTrackedHeadsUpRow;
     private float mAppearFraction;
@@ -96,6 +99,9 @@
     /** Height of the notifications panel without top padding when expansion completes. */
     private float mStackEndHeight;
 
+    /** Whether we are swiping up. */
+    private boolean mIsSwipingUp;
+
     /**
      * @return Height of the notifications panel without top padding when expansion completes.
      */
@@ -133,6 +139,20 @@
     }
 
     /**
+     * @param isSwipingUp Whether we are swiping up.
+     */
+    public void setSwipingUp(boolean isSwipingUp) {
+        mIsSwipingUp = isSwipingUp;
+    }
+
+    /**
+     * @return Whether we are swiping up.
+     */
+    public boolean isSwipingUp() {
+        return mIsSwipingUp;
+    }
+
+    /**
      * @return Fraction of shade expansion.
      */
     public float getExpansionFraction() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 25b8a65..2c4db77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -203,6 +203,9 @@
     private float mQsExpansionFraction;
     private final int mSplitShadeMinContentHeight;
 
+    /** Whether we are flinging the shade open or closed. */
+    private boolean mIsFlinging;
+
     /**
      * The algorithm which calculates the properties for our children
      */
@@ -1270,6 +1273,16 @@
     }
 
     /**
+     * @return Whether we should skip stack height update for lockscreen swipe-up or unlock hint.
+     */
+    private boolean shouldSkipHeightUpdate() {
+        // After the user swipes up on lockscreen and lets go,
+        // {@link PanelViewController) flings the shade back down.
+        return mAmbientState.isOnKeyguard() && (
+                mAmbientState.isUnlockHintRunning() || mAmbientState.isSwipingUp() || mIsFlinging);
+    }
+
+    /**
      * Apply expansion fraction to the y position and height of the notifications panel.
      * @param listenerNeedsAnimation does the listener need to animate?
      */
@@ -1283,7 +1296,7 @@
         if (mOnStackYChanged != null) {
             mOnStackYChanged.accept(listenerNeedsAnimation);
         }
-        if (mQsExpansionFraction <= 0) {
+        if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) {
             final float endHeight = updateStackEndHeight(
                     getHeight(), getEmptyBottomMargin(), mTopPadding);
             updateStackHeight(endHeight, fraction);
@@ -1325,22 +1338,27 @@
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     public void setExpandedHeight(float height) {
         final float shadeBottom = getHeight() - getEmptyBottomMargin();
-        final float expansionFraction = MathUtils.saturate(height / shadeBottom);
-        mAmbientState.setExpansionFraction(expansionFraction);
+        final boolean skipHeightUpdate = shouldSkipHeightUpdate();
+        if (!skipHeightUpdate) {
+            final float expansionFraction = MathUtils.saturate(height / shadeBottom);
+            mAmbientState.setExpansionFraction(expansionFraction);
+        }
         updateStackPosition();
 
-        mExpandedHeight = height;
-        setIsExpanded(height > 0);
-        int minExpansionHeight = getMinExpansionHeight();
-        if (height < minExpansionHeight) {
-            mClipRect.left = 0;
-            mClipRect.right = getWidth();
-            mClipRect.top = 0;
-            mClipRect.bottom = (int) height;
-            height = minExpansionHeight;
-            setRequestedClipBounds(mClipRect);
-        } else {
-            setRequestedClipBounds(null);
+        if (!skipHeightUpdate) {
+            mExpandedHeight = height;
+            setIsExpanded(height > 0);
+            int minExpansionHeight = getMinExpansionHeight();
+            if (height < minExpansionHeight) {
+                mClipRect.left = 0;
+                mClipRect.right = getWidth();
+                mClipRect.top = 0;
+                mClipRect.bottom = (int) height;
+                height = minExpansionHeight;
+                setRequestedClipBounds(mClipRect);
+            } else {
+                setRequestedClipBounds(null);
+            }
         }
         int stackHeight;
         float translationY;
@@ -1368,7 +1386,7 @@
                     }
                 }
             } else {
-                stackHeight = (int) height;
+                stackHeight = (int) (skipHeightUpdate ? mExpandedHeight : height);
             }
         } else {
             appearFraction = calculateAppearFraction(height);
@@ -1386,7 +1404,7 @@
             }
         }
         mAmbientState.setAppearFraction(appearFraction);
-        if (stackHeight != mCurrentStackHeight) {
+        if (stackHeight != mCurrentStackHeight && !skipHeightUpdate) {
             mCurrentStackHeight = stackHeight;
             updateAlgorithmHeightAndPadding();
             requestChildrenUpdate();
@@ -5001,6 +5019,13 @@
         mAmbientState.setUnlockHintRunning(running);
     }
 
+    /**
+     * @param isFlinging Whether we are flinging the shade open or closed.
+     */
+    public void setIsFlinging(boolean isFlinging) {
+        mIsFlinging = isFlinging;
+    }
+
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setHeadsUpGoingAwayAnimationsAllowed(boolean headsUpGoingAwayAnimationsAllowed) {
         mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index a2929f0..e1116f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1195,6 +1195,13 @@
         mView.setUnlockHintRunning(running);
     }
 
+    /**
+     * @param isFlinging Whether we are flinging the shade open or close.
+     */
+    public void setIsFlinging(boolean isFlinging) {
+        mView.setIsFlinging(isFlinging);
+    }
+
     public boolean isFooterViewNotGone() {
         return mView.isFooterViewNotGone();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 1038e76..2d2fbe5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -33,6 +33,7 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -66,9 +67,10 @@
 
     NotificationSwipeHelper(
             Resources resources, ViewConfiguration viewConfiguration,
-            FalsingManager falsingManager, int swipeDirection, NotificationCallback callback,
+            FalsingManager falsingManager, FeatureFlags featureFlags,
+            int swipeDirection, NotificationCallback callback,
             NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
-        super(swipeDirection, callback, resources, viewConfiguration, falsingManager);
+        super(swipeDirection, callback, resources, viewConfiguration, falsingManager, featureFlags);
         mMenuListener = menuListener;
         mCallback = callback;
         mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */);
@@ -508,16 +510,18 @@
         private final Resources mResources;
         private final ViewConfiguration mViewConfiguration;
         private final FalsingManager mFalsingManager;
+        private final FeatureFlags mFeatureFlags;
         private int mSwipeDirection;
         private NotificationCallback mNotificationCallback;
         private NotificationMenuRowPlugin.OnMenuEventListener mOnMenuEventListener;
 
         @Inject
         Builder(@Main Resources resources, ViewConfiguration viewConfiguration,
-                FalsingManager falsingManager) {
+                FalsingManager falsingManager, FeatureFlags featureFlags) {
             mResources = resources;
             mViewConfiguration = viewConfiguration;
             mFalsingManager = falsingManager;
+            mFeatureFlags = featureFlags;
         }
 
         Builder setSwipeDirection(int swipeDirection) {
@@ -538,7 +542,7 @@
 
         NotificationSwipeHelper build() {
             return new NotificationSwipeHelper(mResources, mViewConfiguration, mFalsingManager,
-                    mSwipeDirection, mNotificationCallback, mOnMenuEventListener);
+                    mFeatureFlags, mSwipeDirection, mNotificationCallback, mOnMenuEventListener);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 2ec5f25..b8e9875 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -40,6 +40,8 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
@@ -67,8 +69,10 @@
     private ImageView mMultiUserAvatar;
     private BatteryMeterView mBatteryView;
     private StatusIconContainer mStatusIconContainer;
+    private ViewGroup mUserSwitcherContainer;
 
     private boolean mKeyguardUserSwitcherEnabled;
+    private boolean mKeyguardUserAvatarEnabled;
 
     private boolean mIsPrivacyDotEnabled;
     private int mSystemIconsSwitcherHiddenExpandedMargin;
@@ -111,10 +115,15 @@
         mCutoutSpace = findViewById(R.id.cutout_space_view);
         mStatusIconArea = findViewById(R.id.status_icon_area);
         mStatusIconContainer = findViewById(R.id.statusIcons);
+        mUserSwitcherContainer = findViewById(R.id.user_switcher_container);
         mIsPrivacyDotEnabled = mContext.getResources().getBoolean(R.bool.config_enablePrivacyDot);
         loadDimens();
     }
 
+    public ViewGroup getUserSwitcherContainer() {
+        return mUserSwitcherContainer;
+    }
+
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
@@ -186,6 +195,17 @@
     }
 
     private void updateVisibilities() {
+        // Multi user avatar is disabled in favor of the user switcher chip
+        if (!mKeyguardUserAvatarEnabled) {
+            if (mMultiUserAvatar.getParent() == mStatusIconArea) {
+                mStatusIconArea.removeView(mMultiUserAvatar);
+            } else if (mMultiUserAvatar.getParent() != null) {
+                getOverlay().remove(mMultiUserAvatar);
+            }
+
+            return;
+        }
+
         if (mMultiUserAvatar.getParent() != mStatusIconArea
                 && !mKeyguardUserSwitcherEnabled) {
             if (mMultiUserAvatar.getParent() != null) {
@@ -346,6 +366,16 @@
         mKeyguardUserSwitcherEnabled = enabled;
     }
 
+    void setKeyguardUserAvatarEnabled(boolean enabled) {
+        mKeyguardUserAvatarEnabled = enabled;
+        updateVisibilities();
+    }
+
+    @VisibleForTesting
+    boolean isKeyguardUserAvatarEnabled() {
+        return mKeyguardUserAvatarEnabled;
+    }
+
     private void animateNextLayoutChange() {
         final int systemIconsCurrentX = mSystemIconsContainer.getLeft();
         final boolean userAvatarVisible = mMultiUserAvatar.getParent() == mStatusIconArea;
@@ -416,9 +446,14 @@
 
     /** Should only be called from {@link KeyguardStatusBarViewController}. */
     void onOverlayChanged() {
-        mCarrierLabel.setTextAppearance(
-                Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall));
+        int theme = Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall);
+        mCarrierLabel.setTextAppearance(theme);
         mBatteryView.updatePercentView();
+
+        TextView userSwitcherName = mUserSwitcherContainer.findViewById(R.id.current_user_name);
+        if (userSwitcherName != null) {
+            userSwitcherName.setTextAppearance(theme);
+        }
     }
 
     private void updateIconsAndTextColors(StatusBarIconController.TintedIconManager iconManager) {
@@ -429,6 +464,14 @@
                 R.color.light_mode_icon_color_single_tone);
         float intensity = textColor == Color.WHITE ? 0 : 1;
         mCarrierLabel.setTextColor(iconColor);
+
+        TextView userSwitcherName = mUserSwitcherContainer.findViewById(R.id.current_user_name);
+        if (userSwitcherName != null) {
+            userSwitcherName.setTextColor(Utils.getColorStateListDefaultColor(
+                    mContext,
+                    R.color.light_mode_icon_color_single_tone));
+        }
+
         if (iconManager != null) {
             iconManager.setTint(iconColor);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index ee97fd6..1df1aff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -47,6 +47,9 @@
 import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserInfoTracker;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherFeatureController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -95,6 +98,9 @@
     private final SysuiStatusBarStateController mStatusBarStateController;
     private final StatusBarContentInsetsProvider mInsetsProvider;
     private final UserManager mUserManager;
+    private final StatusBarUserSwitcherFeatureController mFeatureController;
+    private final StatusBarUserSwitcherController mUserSwitcherController;
+    private final StatusBarUserInfoTracker mStatusBarUserInfoTracker;
 
     private final ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
@@ -246,7 +252,10 @@
             BiometricUnlockController biometricUnlockController,
             SysuiStatusBarStateController statusBarStateController,
             StatusBarContentInsetsProvider statusBarContentInsetsProvider,
-            UserManager userManager
+            UserManager userManager,
+            StatusBarUserSwitcherFeatureController featureController,
+            StatusBarUserSwitcherController userSwitcherController,
+            StatusBarUserInfoTracker statusBarUserInfoTracker
     ) {
         super(view);
         mCarrierTextController = carrierTextController;
@@ -265,6 +274,9 @@
         mStatusBarStateController = statusBarStateController;
         mInsetsProvider = statusBarContentInsetsProvider;
         mUserManager = userManager;
+        mFeatureController = featureController;
+        mUserSwitcherController = userSwitcherController;
+        mStatusBarUserInfoTracker = statusBarUserInfoTracker;
 
         mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
         mKeyguardStateController.addCallback(
@@ -286,6 +298,10 @@
                 r.getString(com.android.internal.R.string.status_bar_call_strength)));
         mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
                 R.dimen.header_notifications_collide_distance);
+
+        mView.setKeyguardUserAvatarEnabled(
+                !mFeatureController.isStatusBarUserSwitcherFeatureEnabled());
+        mFeatureController.addCallback(enabled -> mView.setKeyguardUserAvatarEnabled(!enabled));
     }
 
     @Override
@@ -293,6 +309,7 @@
         super.onInit();
         mCarrierTextController.init();
         mBatteryMeterViewController.init();
+        mUserSwitcherController.init();
     }
 
     @Override
@@ -334,6 +351,9 @@
     /** Sets whether user switcher is enabled. */
     public void setKeyguardUserSwitcherEnabled(boolean enabled) {
         mView.setKeyguardUserSwitcherEnabled(enabled);
+        // We don't have a listener for when the user switcher setting changes, so this is
+        // where we re-check the state
+        mStatusBarUserInfoTracker.checkEnabled();
     }
 
     /** Sets whether this controller should listen to battery updates. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 3d3a1da..278b4ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -806,7 +806,6 @@
             QsFrameTranslateController qsFrameTranslateController,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController) {
         super(view,
-                featureFlags,
                 falsingManager,
                 dozeLog,
                 keyguardStateController,
@@ -1885,9 +1884,16 @@
         mHeadsUpTouchHelper.notifyFling(!expand);
         mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */);
         setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
+        mNotificationStackScrollLayoutController.setIsFlinging(true);
         super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
     }
 
+    @Override
+    protected void onFlingEnd(boolean cancelled) {
+        super.onFlingEnd(cancelled);
+        mNotificationStackScrollLayoutController.setIsFlinging(false);
+    }
+
     private boolean onQsIntercept(MotionEvent event) {
         int pointerIndex = event.findPointerIndex(mTrackingPointer);
         if (pointerIndex < 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 474653b..9f9e7d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -310,10 +310,8 @@
             if (onKeyguard
                     && mAuthController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())) {
                 mLpChanged.preferredMaxDisplayRefreshRate = mKeyguardPreferredRefreshRate;
-                mLpChanged.preferredMinDisplayRefreshRate = mKeyguardPreferredRefreshRate;
             } else {
                 mLpChanged.preferredMaxDisplayRefreshRate = 0;
-                mLpChanged.preferredMinDisplayRefreshRate = 0;
             }
             Trace.setCounter("display_set_preferred_refresh_rate",
                     (long) mKeyguardPreferredRefreshRate);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index c466a8c..85e8042 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -53,8 +53,6 @@
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.doze.DozeLog;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -223,7 +221,6 @@
 
     public PanelViewController(
             PanelView view,
-            FeatureFlags featureFlags,
             FalsingManager falsingManager,
             DozeLog dozeLog,
             KeyguardStateController keyguardStateController,
@@ -292,7 +289,8 @@
         mBounceInterpolator = new BounceInterpolator();
         mFalsingManager = falsingManager;
         mDozeLog = dozeLog;
-        mNotificationsDragEnabled = featureFlags.isEnabled(Flags.NOTIFICATION_SHADE_DRAG);
+        mNotificationsDragEnabled = mResources.getBoolean(
+                R.bool.config_enableNotificationShadeDrag);
         mVibratorHelper = vibratorHelper;
         mVibrateOnOpening = mResources.getBoolean(R.bool.config_vibrateOnIconAnimation);
         mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
@@ -461,7 +459,7 @@
             boolean expands = onEmptySpaceClick(mInitialTouchX);
             onTrackingStopped(expands);
         }
-
+        mAmbientState.setSwipingUp(false);
         mVelocityTracker.clear();
     }
 
@@ -708,7 +706,7 @@
         animator.start();
     }
 
-    private void onFlingEnd(boolean cancelled) {
+    void onFlingEnd(boolean cancelled) {
         mIsFlinging = false;
         // No overshoot when the animation ends
         setOverExpansionInternal(0, false /* isFromGesture */);
@@ -1393,6 +1391,10 @@
                         mUpwardsWhenThresholdReached = isDirectionUpwards(x, y);
                     }
                     if ((!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {
+                        // Count h==0 as part of swipe-up,
+                        // otherwise {@link NotificationStackScrollLayout}
+                        // wrongly enables stack height updates at the start of lockscreen swipe-up
+                        mAmbientState.setSwipingUp(h <= 0);
                         setExpandedHeightInternal(newHeight);
                     }
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index d6bf5f2..224b2e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -21,15 +21,19 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewTreeObserver
+
 import com.android.systemui.R
 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.UNFOLD_STATUS_BAR
 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
 import com.android.systemui.util.ViewController
 import com.android.systemui.util.kotlin.getOrNull
+
 import java.util.Optional
+
 import javax.inject.Inject
 import javax.inject.Named
 
@@ -38,6 +42,7 @@
     view: PhoneStatusBarView,
     @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
     private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
+    private val userSwitcherController: StatusBarUserSwitcherController,
     touchEventHandler: PhoneStatusBarView.TouchEventHandler,
     private val configurationController: ConfigurationController
 ) : ViewController<PhoneStatusBarView>(view) {
@@ -89,6 +94,10 @@
         mView.setTouchEventHandler(touchEventHandler)
     }
 
+    override fun onInit() {
+        userSwitcherController.init()
+    }
+
     fun setImportantForAccessibility(mode: Int) {
         mView.importantForAccessibility = mode
     }
@@ -153,6 +162,7 @@
         private val unfoldComponent: Optional<SysUIUnfoldComponent>,
         @Named(UNFOLD_STATUS_BAR)
         private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
+        private val userSwitcherController: StatusBarUserSwitcherController,
         private val configurationController: ConfigurationController
     ) {
         fun create(
@@ -163,6 +173,7 @@
                 view,
                 progressProvider.getOrNull(),
                 unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController(),
+                userSwitcherController,
                 touchEventHandler,
                 configurationController
             )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 3292934..d464acb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -217,8 +217,10 @@
      * frameworks/base/core/res/res/values/config.xml
      */
     public void addIgnoredSlot(String slotName) {
-        addIgnoredSlotInternal(slotName);
-        requestLayout();
+        boolean added = addIgnoredSlotInternal(slotName);
+        if (added) {
+            requestLayout();
+        }
     }
 
     /**
@@ -226,17 +228,27 @@
      * @param slots names of the icons to ignore
      */
     public void addIgnoredSlots(List<String> slots) {
+        boolean willAddAny = false;
         for (String slot : slots) {
-            addIgnoredSlotInternal(slot);
+            willAddAny |= addIgnoredSlotInternal(slot);
         }
 
-        requestLayout();
+        if (willAddAny) {
+            requestLayout();
+        }
     }
 
-    private void addIgnoredSlotInternal(String slotName) {
-        if (!mIgnoredSlots.contains(slotName)) {
-            mIgnoredSlots.add(slotName);
+    /**
+     *
+     * @param slotName
+     * @return
+     */
+    private boolean addIgnoredSlotInternal(String slotName) {
+        if (mIgnoredSlots.contains(slotName)) {
+            return false;
         }
+        mIgnoredSlots.add(slotName);
+        return true;
     }
 
     /**
@@ -245,9 +257,10 @@
      * @param slotName name of the icon slot to remove from the ignored list
      */
     public void removeIgnoredSlot(String slotName) {
-        mIgnoredSlots.remove(slotName);
-
-        requestLayout();
+        boolean removed = mIgnoredSlots.remove(slotName);
+        if (removed) {
+            requestLayout();
+        }
     }
 
     /**
@@ -256,11 +269,14 @@
      * @param slots name of the icon slots to remove from the ignored list
      */
     public void removeIgnoredSlots(List<String> slots) {
+        boolean removedAny = false;
         for (String slot : slots) {
-            mIgnoredSlots.remove(slot);
+            removedAny |= mIgnoredSlots.remove(slot);
         }
 
-        requestLayout();
+        if (removedAny) {
+            requestLayout();
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
index dea1b43..e2dc905 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
@@ -26,11 +26,15 @@
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherControllerImpl;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
 
 import javax.inject.Named;
 
+import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
 
@@ -83,6 +87,20 @@
     /** */
     @Provides
     @StatusBarFragmentScope
+    static StatusBarUserSwitcherContainer provideStatusBarUserSwitcherContainer(
+            @RootView PhoneStatusBarView view) {
+        return view.findViewById(R.id.user_switcher_container);
+    }
+
+    /** */
+    @Binds
+    @StatusBarFragmentScope
+    StatusBarUserSwitcherController bindStatusBarUserSwitcherController(
+            StatusBarUserSwitcherControllerImpl controller);
+
+    /** */
+    @Provides
+    @StatusBarFragmentScope
     static PhoneStatusBarViewController providePhoneStatusBarViewController(
             PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory,
             @RootView PhoneStatusBarView phoneStatusBarView,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt
new file mode 100644
index 0000000..2dbc19c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.userswitcher
+
+import android.graphics.drawable.Drawable
+import android.os.UserManager
+
+import com.android.systemui.DejankUtils.whitelistIpcs
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.CallbackController
+import com.android.systemui.statusbar.policy.UserInfoController
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
+
+import javax.inject.Inject
+
+/**
+ * Since every user switcher chip will user the exact same information and logic on whether or not
+ * to show, and what data to show, it makes sense to create a single tracker here
+ */
+@SysUISingleton
+class StatusBarUserInfoTracker @Inject constructor(
+    private val userInfoController: UserInfoController,
+    private val userManager: UserManager
+) : CallbackController<CurrentUserChipInfoUpdatedListener> {
+    var currentUserName: String? = null
+        private set
+    var currentUserAvatar: Drawable? = null
+        private set
+    var userSwitcherEnabled = false
+        private set
+    private var listening = false
+
+    private val listeners = mutableListOf<CurrentUserChipInfoUpdatedListener>()
+
+    private val userInfoChangedListener = OnUserInfoChangedListener { name, picture, _ ->
+        currentUserAvatar = picture
+        currentUserName = name
+        notifyListenersUserInfoChanged()
+    }
+
+    init {
+        startListening()
+    }
+
+    override fun addCallback(listener: CurrentUserChipInfoUpdatedListener) {
+        if (listeners.isEmpty()) {
+            startListening()
+        }
+
+        if (!listeners.contains(listener)) {
+            listeners.add(listener)
+        }
+    }
+
+    override fun removeCallback(listener: CurrentUserChipInfoUpdatedListener) {
+        listeners.remove(listener)
+
+        if (listeners.isEmpty()) {
+            stopListening()
+        }
+    }
+
+    private fun notifyListenersUserInfoChanged() {
+        listeners.forEach {
+            it.onCurrentUserChipInfoUpdated()
+        }
+    }
+
+    private fun notifyListenersSettingChanged() {
+        listeners.forEach {
+            it.onStatusBarUserSwitcherSettingChanged(userSwitcherEnabled)
+        }
+    }
+
+    private fun startListening() {
+        listening = true
+        userInfoController.addCallback(userInfoChangedListener)
+    }
+
+    private fun stopListening() {
+        listening = false
+        userInfoController.removeCallback(userInfoChangedListener)
+    }
+
+    private fun checkUserSwitcherEnabled() {
+        whitelistIpcs {
+            userSwitcherEnabled = userManager.isUserSwitcherEnabled
+        }
+    }
+
+    /**
+     * Force a check to [UserManager.isUserSwitcherEnabled], and update listeners if the value has
+     * changed
+     */
+    fun checkEnabled() {
+        val wasEnabled = userSwitcherEnabled
+        checkUserSwitcherEnabled()
+
+        if (wasEnabled != userSwitcherEnabled) {
+            notifyListenersSettingChanged()
+        }
+    }
+}
+
+interface CurrentUserChipInfoUpdatedListener {
+    fun onCurrentUserChipInfoUpdated()
+    fun onStatusBarUserSwitcherSettingChanged(enabled: Boolean) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
new file mode 100644
index 0000000..2c8677d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.userswitcher
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.systemui.R
+
+class StatusBarUserSwitcherContainer(
+    context: Context?,
+    attrs: AttributeSet?
+) : LinearLayout(context, attrs) {
+    lateinit var text: TextView
+        private set
+    lateinit var avatar: ImageView
+        private set
+
+    override fun onFinishInflate() {
+        super.onFinishInflate()
+        text = findViewById(R.id.current_user_name)
+        avatar = findViewById(R.id.current_user_avatar)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
new file mode 100644
index 0000000..a124753
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.userswitcher
+
+import android.view.View
+
+import com.android.systemui.qs.user.UserSwitchDialogController
+import com.android.systemui.util.ViewController
+
+import javax.inject.Inject
+
+/**
+ * ViewController for [StatusBarUserSwitcherContainer]
+ */
+class StatusBarUserSwitcherControllerImpl @Inject constructor(
+    view: StatusBarUserSwitcherContainer,
+    private val tracker: StatusBarUserInfoTracker,
+    private val featureController: StatusBarUserSwitcherFeatureController,
+    private val userSwitcherDialogController: UserSwitchDialogController
+) : ViewController<StatusBarUserSwitcherContainer>(view),
+        StatusBarUserSwitcherController {
+    private val listener = object : CurrentUserChipInfoUpdatedListener {
+        override fun onCurrentUserChipInfoUpdated() {
+            updateChip()
+        }
+
+        override fun onStatusBarUserSwitcherSettingChanged(enabled: Boolean) {
+            updateEnabled()
+        }
+    }
+
+    private val featureFlagListener = object : OnUserSwitcherPreferenceChangeListener {
+        override fun onUserSwitcherPreferenceChange(enabled: Boolean) {
+            updateEnabled()
+        }
+    }
+
+    override fun onViewAttached() {
+        tracker.addCallback(listener)
+        featureController.addCallback(featureFlagListener)
+        mView.setOnClickListener {
+            userSwitcherDialogController.showDialog(it)
+        }
+
+        updateEnabled()
+    }
+
+    override fun onViewDetached() {
+        tracker.removeCallback(listener)
+        featureController.removeCallback(featureFlagListener)
+        mView.setOnClickListener(null)
+    }
+
+    private fun updateChip() {
+        mView.text.text = tracker.currentUserName
+        mView.avatar.setImageDrawable(tracker.currentUserAvatar)
+    }
+
+    private fun updateEnabled() {
+        if (featureController.isStatusBarUserSwitcherFeatureEnabled() &&
+                tracker.userSwitcherEnabled) {
+            mView.visibility = View.VISIBLE
+            updateChip()
+        } else {
+            mView.visibility = View.GONE
+        }
+    }
+}
+
+interface StatusBarUserSwitcherController {
+    fun init()
+}
+
+private const val TAG = "SbUserSwitcherController"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt
new file mode 100644
index 0000000..7bae9ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.userswitcher
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.policy.CallbackController
+
+import javax.inject.Inject
+
+@SysUISingleton
+class StatusBarUserSwitcherFeatureController @Inject constructor(
+    private val flags: FeatureFlags
+) : CallbackController<OnUserSwitcherPreferenceChangeListener> {
+    private val listeners = mutableListOf<OnUserSwitcherPreferenceChangeListener>()
+
+    init {
+        flags.addListener(Flags.STATUS_BAR_USER_SWITCHER) {
+            it.requestNoRestart()
+            notifyListeners()
+        }
+    }
+
+    fun isStatusBarUserSwitcherFeatureEnabled(): Boolean {
+        return flags.isEnabled(Flags.STATUS_BAR_USER_SWITCHER)
+    }
+
+    override fun addCallback(listener: OnUserSwitcherPreferenceChangeListener) {
+        if (!listeners.contains(listener)) {
+            listeners.add(listener)
+        }
+    }
+
+    override fun removeCallback(listener: OnUserSwitcherPreferenceChangeListener) {
+        listeners.remove(listener)
+    }
+
+    private fun notifyListeners() {
+        val enabled = flags.isEnabled(Flags.STATUS_BAR_USER_SWITCHER)
+        listeners.forEach {
+            it.onUserSwitcherPreferenceChange(enabled)
+        }
+    }
+}
+
+interface OnUserSwitcherPreferenceChangeListener {
+    fun onUserSwitcherPreferenceChange(enabled: Boolean)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 3084a95..784a5468 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -350,11 +350,14 @@
      * @return -1 if the first argument should be ranked higher than the second, 1 if the second
      * one should be ranked higher and 0 if they are equal.
      */
-    public int compare(@NonNull NotificationEntry a, @NonNull NotificationEntry b) {
+    public int compare(@Nullable NotificationEntry a, @Nullable NotificationEntry b) {
+        if (a == null || b == null) {
+            return Boolean.compare(a == null, b == null);
+        }
         AlertEntry aEntry = getHeadsUpEntry(a.getKey());
         AlertEntry bEntry = getHeadsUpEntry(b.getKey());
         if (aEntry == null || bEntry == null) {
-            return aEntry == null ? 1 : -1;
+            return Boolean.compare(aEntry == null, bEntry == null);
         }
         return aEntry.compareTo(bEntry);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt
deleted file mode 100644
index c6dbdb1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.systemui.statusbar.policy
-
-/**
- * Interface for tracking packages with running foreground services and demoting foreground status
- */
-interface RunningFgsController : CallbackController<RunningFgsController.Callback> {
-
-    /**
-     * @return A list of [UserPackageTime]s which have running foreground service(s)
-     */
-    fun getPackagesWithFgs(): List<UserPackageTime>
-
-    /**
-     * Stops all foreground services running as a package
-     * @param userId the userId the package is running under
-     * @param packageName the packageName
-     */
-    fun stopFgs(userId: Int, packageName: String)
-
-    /**
-     * Returns when the list of packages with foreground services changes
-     */
-    interface Callback {
-        /**
-         * The thing that
-         * @param packages the list of packages
-         */
-        fun onFgsPackagesChanged(packages: List<UserPackageTime>)
-    }
-
-    /**
-     * A triplet <user, packageName, timeMillis> where each element is a package running
-     * under a user that has had at least one foreground service running since timeMillis.
-     * Time should be derived from [SystemClock.elapsedRealtime].
-     */
-    data class UserPackageTime(val userId: Int, val packageName: String, val startTimeMillis: Long)
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt
deleted file mode 100644
index 6d3345d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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.systemui.statusbar.policy
-
-import android.app.IActivityManager
-import android.app.IForegroundServiceObserver
-import android.os.IBinder
-import android.os.RemoteException
-import android.util.Log
-import androidx.annotation.GuardedBy
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleOwner
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.statusbar.policy.RunningFgsController.Callback
-import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime
-import com.android.systemui.util.time.SystemClock
-import java.util.concurrent.Executor
-import javax.inject.Inject
-
-/**
- * Implementation for [RunningFgsController]
- */
-@SysUISingleton
-class RunningFgsControllerImpl @Inject constructor(
-    @Background private val executor: Executor,
-    private val systemClock: SystemClock,
-    private val activityManager: IActivityManager
-) : RunningFgsController, IForegroundServiceObserver.Stub() {
-
-    companion object {
-        private val LOG_TAG = RunningFgsControllerImpl::class.java.simpleName
-    }
-
-    private val lock = Any()
-
-    @GuardedBy("lock")
-    var initialized = false
-
-    @GuardedBy("lock")
-    private val runningServiceTokens = mutableMapOf<UserPackageKey, StartTimeAndTokensValue>()
-
-    @GuardedBy("lock")
-    private val callbacks = mutableSetOf<Callback>()
-
-    fun init() {
-        synchronized(lock) {
-            if (initialized) {
-                return
-            }
-            try {
-                activityManager.registerForegroundServiceObserver(this)
-            } catch (e: RemoteException) {
-                e.rethrowFromSystemServer()
-            }
-
-            initialized = true
-        }
-    }
-
-    override fun addCallback(listener: Callback) {
-        init()
-        synchronized(lock) { callbacks.add(listener) }
-    }
-
-    override fun removeCallback(listener: Callback) {
-        init()
-        synchronized(lock) {
-            if (!callbacks.remove(listener)) {
-                Log.e(LOG_TAG, "Callback was not registered.", RuntimeException())
-            }
-        }
-    }
-
-    override fun observe(lifecycle: Lifecycle?, listener: Callback?): Callback {
-        init()
-        return super.observe(lifecycle, listener)
-    }
-
-    override fun observe(owner: LifecycleOwner?, listener: Callback?): Callback {
-        init()
-        return super.observe(owner, listener)
-    }
-
-    override fun getPackagesWithFgs(): List<UserPackageTime> {
-        init()
-        return synchronized(lock) { getPackagesWithFgsLocked() }
-    }
-
-    private fun getPackagesWithFgsLocked(): List<UserPackageTime> =
-            runningServiceTokens.map {
-                UserPackageTime(it.key.userId, it.key.packageName, it.value.fgsStartTime)
-            }
-
-    override fun stopFgs(userId: Int, packageName: String) {
-        init()
-        try {
-            activityManager.stopAppForUser(packageName, userId)
-        } catch (e: RemoteException) {
-            e.rethrowFromSystemServer()
-        }
-    }
-
-    private data class UserPackageKey(
-        val userId: Int,
-        val packageName: String
-    )
-
-    private class StartTimeAndTokensValue(systemClock: SystemClock) {
-        val fgsStartTime = systemClock.elapsedRealtime()
-        var tokens = mutableSetOf<IBinder>()
-        fun addToken(token: IBinder): Boolean {
-            return tokens.add(token)
-        }
-
-        fun removeToken(token: IBinder): Boolean {
-            return tokens.remove(token)
-        }
-
-        val isEmpty: Boolean
-            get() = tokens.isEmpty()
-    }
-
-    override fun onForegroundStateChanged(
-        token: IBinder,
-        packageName: String,
-        userId: Int,
-        isForeground: Boolean
-    ) {
-        val result = synchronized(lock) {
-            val userPackageKey = UserPackageKey(userId, packageName)
-            if (isForeground) {
-                var addedNew = false
-                runningServiceTokens.getOrPut(userPackageKey) {
-                    addedNew = true
-                    StartTimeAndTokensValue(systemClock)
-                }.addToken(token)
-                if (!addedNew) {
-                    return
-                }
-            } else {
-                val startTimeAndTokensValue = runningServiceTokens[userPackageKey]
-                if (startTimeAndTokensValue?.removeToken(token) == false) {
-                    Log.e(LOG_TAG,
-                            "Stopped foreground service was not known to be running.")
-                    return
-                }
-                if (!startTimeAndTokensValue!!.isEmpty) {
-                    return
-                }
-                runningServiceTokens.remove(userPackageKey)
-            }
-            getPackagesWithFgsLocked().toList()
-        }
-
-        callbacks.forEach { executor.execute { it.onFgsPackagesChanged(result) } }
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/AutoMarqueeTextView.java b/packages/SystemUI/src/com/android/systemui/util/AutoMarqueeTextView.java
index 09dbfee..fa4f314 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AutoMarqueeTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AutoMarqueeTextView.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.widget.TextView;
 
 /**
  * TextView that changes its ellipsize value with its visibility.
@@ -27,7 +26,7 @@
  * The View responds to changes in user-visibility to change its ellipsize from MARQUEE to END
  * and back. Useful for TextView that need to marquee forever.
  */
-public class AutoMarqueeTextView extends TextView {
+public class AutoMarqueeTextView extends SafeMarqueeTextView {
 
     private boolean mAggregatedVisible = false;
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/SafeMarqueeTextView.kt b/packages/SystemUI/src/com/android/systemui/util/SafeMarqueeTextView.kt
new file mode 100644
index 0000000..1c1a990
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/SafeMarqueeTextView.kt
@@ -0,0 +1,44 @@
+package com.android.systemui.util
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.ViewGroup
+import android.widget.TextView
+
+/**
+ * A TextField that doesn't relayout when changing from marquee to ellipsis.
+ */
+@SuppressLint("AppCompatCustomView")
+open class SafeMarqueeTextView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0,
+    defStyleRes: Int = 0
+) : TextView(context, attrs, defStyleAttr, defStyleRes) {
+
+    private var safelyIgnoreLayout = false
+    private val hasStableWidth
+        get() = layoutParams.width != ViewGroup.LayoutParams.WRAP_CONTENT
+
+    override fun requestLayout() {
+        if (safelyIgnoreLayout) {
+            return
+        }
+        super.requestLayout()
+    }
+
+    override fun startMarquee() {
+        val wasIgnoring = safelyIgnoreLayout
+        safelyIgnoreLayout = hasStableWidth
+        super.startMarquee()
+        safelyIgnoreLayout = wasIgnoring
+    }
+
+    override fun stopMarquee() {
+        val wasIgnoring = safelyIgnoreLayout
+        safelyIgnoreLayout = hasStableWidth
+        super.stopMarquee()
+        safelyIgnoreLayout = wasIgnoring
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 407dc5e..71d8e33 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -162,6 +162,14 @@
     }
 
     /**
+     * Returns true if the device should use the collapsed layout for the media player when in
+     * landscape (or seascape) orientation
+     */
+    public static boolean useCollapsedMediaInLandscape(Resources resources) {
+        return resources.getBoolean(R.bool.config_quickSettingsMediaLandscapeCollapsed);
+    }
+
+    /**
      * Returns true if the device should use the split notification shade, based on orientation and
      * screen width.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
new file mode 100644
index 0000000..b506808
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
@@ -0,0 +1,123 @@
+package com.android.systemui.util.drawable
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.Animatable
+import android.graphics.drawable.Animatable2
+import android.graphics.drawable.AnimatedImageDrawable
+import android.graphics.drawable.AnimatedRotateDrawable
+import android.graphics.drawable.AnimatedStateListDrawable
+import android.graphics.drawable.AnimatedVectorDrawable
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.util.Log
+import androidx.annotation.Px
+import com.android.systemui.util.traceSection
+
+class DrawableSize {
+
+    companion object {
+
+        const val TAG = "SysUiDrawableSize"
+
+        /**
+         * Downscales passed Drawable to set maximum width and height. This will only
+         * be done for Drawables that can be downscaled non-destructively - e.g. animated
+         * and stateful drawables will no be downscaled.
+         *
+         * Downscaling will keep the aspect ratio.
+         * This method will not touch drawables that already fit into size specification.
+         *
+         * @param resources Resources on which to base the density of resized drawable.
+         * @param drawable Drawable to downscale.
+         * @param maxWidth Maximum width of the downscaled drawable.
+         * @param maxHeight Maximum height of the downscaled drawable.
+         *
+         * @return returns downscaled drawable if it's possible to downscale it or original if it's
+         *         not.
+         */
+        @JvmStatic
+        fun downscaleToSize(
+            res: Resources,
+            drawable: Drawable,
+            @Px maxWidth: Int,
+            @Px maxHeight: Int
+        ): Drawable {
+            traceSection("DrawableSize#downscaleToSize") {
+                // Bitmap drawables can contain big bitmaps as their content while sneaking it past
+                // us using density scaling. Inspect inside the Bitmap drawables for actual bitmap
+                // size for those.
+                val originalWidth = (drawable as? BitmapDrawable)?.bitmap?.width
+                                    ?: drawable.intrinsicWidth
+                val originalHeight = (drawable as? BitmapDrawable)?.bitmap?.height
+                                    ?: drawable.intrinsicHeight
+
+                // Don't touch drawable if we can't resolve sizes for whatever reason.
+                if (originalWidth <= 0 || originalHeight <= 0) {
+                    return drawable
+                }
+
+                // Do not touch drawables that are already within bounds.
+                if (originalWidth < maxWidth && originalHeight < maxHeight) {
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        Log.d(TAG, "Not resizing $originalWidth x $originalHeight" + " " +
+                                "to $maxWidth x $maxHeight")
+                    }
+
+                    return drawable
+                }
+
+                if (!isSimpleBitmap(drawable)) {
+                    return drawable
+                }
+
+                val scaleWidth = maxWidth.toFloat() / originalWidth.toFloat()
+                val scaleHeight = maxHeight.toFloat() / originalHeight.toFloat()
+                val scale = minOf(scaleHeight, scaleWidth)
+
+                val width = (originalWidth * scale).toInt()
+                val height = (originalHeight * scale).toInt()
+
+                if (width <= 0 || height <= 0) {
+                    Log.w(TAG, "Attempted to resize ${drawable.javaClass.simpleName} " +
+                            "from $originalWidth x $originalHeight to invalid $width x $height.")
+                    return drawable
+                }
+
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Resizing large drawable (${drawable.javaClass.simpleName}) " +
+                            "from $originalWidth x $originalHeight to $width x $height")
+                }
+
+                // We want to keep existing config if it's more efficient than 32-bit RGB.
+                val config = (drawable as? BitmapDrawable)?.bitmap?.config
+                        ?: Bitmap.Config.ARGB_8888
+                val scaledDrawableBitmap = Bitmap.createBitmap(width, height, config)
+                val canvas = Canvas(scaledDrawableBitmap)
+
+                val originalBounds = drawable.bounds
+                drawable.setBounds(0, 0, width, height)
+                drawable.draw(canvas)
+                drawable.bounds = originalBounds
+
+                return BitmapDrawable(res, scaledDrawableBitmap)
+            }
+        }
+
+        private fun isSimpleBitmap(drawable: Drawable): Boolean {
+            return !(drawable.isStateful || isAnimated(drawable))
+        }
+
+        private fun isAnimated(drawable: Drawable): Boolean {
+            if (drawable is Animatable || drawable is Animatable2) {
+                return true
+            }
+
+            return drawable is AnimatedImageDrawable ||
+                drawable is AnimatedRotateDrawable ||
+                drawable is AnimatedStateListDrawable ||
+                drawable is AnimatedVectorDrawable
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java b/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
index 089650c..8215360 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/DumpTruck.java
@@ -50,7 +50,7 @@
     private static final int BUFSIZ = 1024 * 1024; // 1MB
 
     private final Context context;
-    private GarbageMonitor mGarbageMonitor;
+    private final GarbageMonitor mGarbageMonitor;
     private Uri hprofUri;
     private long rss;
     final StringBuilder body = new StringBuilder();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
index b951345..61e78f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -43,7 +43,7 @@
     @Before
     fun setUp() {
         dialogLaunchAnimator = DialogLaunchAnimator(
-            dreamManager, launchAnimator, isForTesting = true)
+            dreamManager, launchAnimator, forceDisableSynchronization = true)
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 35dca7e..7fc354f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.DozeTriggers.DozingUpdateUiEvent;
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -90,6 +91,8 @@
     private KeyguardStateController mKeyguardStateController;
     @Mock
     private DevicePostureController mDevicePostureController;
+    @Mock
+    private BatteryController mBatteryController;
 
     private DozeTriggers mTriggers;
     private FakeSensorManager mSensors;
@@ -122,7 +125,7 @@
                 asyncSensorManager, wakeLock, mDockManager, mProximitySensor,
                 mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings(),
                 mAuthController, mExecutor, mUiEventLogger, mKeyguardStateController,
-                mDevicePostureController);
+                mDevicePostureController, mBatteryController);
         mTriggers.setDozeMachine(mMachine);
         waitForSensorManager();
     }
@@ -230,7 +233,9 @@
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
 
         // WHEN the pick up gesture is triggered and keyguard isn't occluded
+        // and device isn't on a wireless charger
         when(mKeyguardStateController.isOccluded()).thenReturn(false);
+        when(mBatteryController.isPluggedInWireless()).thenReturn(false);
         mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
 
         // THEN wakeup
@@ -244,6 +249,22 @@
 
         // WHEN the pick up gesture is triggered and keyguard IS occluded
         when(mKeyguardStateController.isOccluded()).thenReturn(true);
+        when(mBatteryController.isPluggedInWireless()).thenReturn(false);
+        mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
+
+        // THEN never wakeup
+        verify(mMachine, never()).wakeUp();
+    }
+
+    @Test
+    public void testPickupGestureWirelessCharger() {
+        // GIVEN device is in doze (screen blank, but running doze sensors)
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+
+        // WHEN the pick up gesture is triggered
+        // and device IS on a wireless charger
+        when(mKeyguardStateController.isOccluded()).thenReturn(false);
+        when(mBatteryController.isPluggedInWireless()).thenReturn(true);
         mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
 
         // THEN never wakeup
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 1a8326f..cad98f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -32,6 +32,7 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -117,6 +118,7 @@
     /**
      * Ensures expansion only happens when touch down happens in valid part of the screen.
      */
+    @FlakyTest
     @Test
     public void testSessionStart() {
         mTouchHandler.onSessionStart(mTouchSession);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index d1f505b..51c2580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -90,6 +90,7 @@
     private DozeParameters mDozeParameters;
     @Mock
     private NextAlarmController mNextAlarmController;
+    @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private TestableKeyguardSliceProvider mProvider;
     private boolean mIsZenMode;
@@ -97,7 +98,6 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mKeyguardUpdateMonitor = mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
         mIsZenMode = false;
         mProvider = new TestableKeyguardSliceProvider();
         mProvider.setContextAvailableCallback(context -> { });
@@ -265,6 +265,7 @@
             mStatusBarStateController = KeyguardSliceProviderTest.this.mStatusBarStateController;
             mKeyguardBypassController = KeyguardSliceProviderTest.this.mKeyguardBypassController;
             mMediaManager = KeyguardSliceProviderTest.this.mNotificationMediaManager;
+            mKeyguardUpdateMonitor = KeyguardSliceProviderTest.this.mKeyguardUpdateMonitor;
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index dc7026d..1484c9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -36,6 +36,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
 import org.mockito.Mockito.`when` as whenever
 
@@ -51,6 +52,8 @@
     private lateinit var statusBarStateController: SysuiStatusBarStateController
     @Mock
     private lateinit var configurationController: ConfigurationController
+    @Mock
+    private lateinit var mediaFlags: MediaFlags
 
     @Mock
     private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
@@ -70,13 +73,15 @@
                 .thenReturn(true)
         whenever(mediaHost.hostView).thenReturn(hostView)
         hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
+        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
         keyguardMediaController = KeyguardMediaController(
             mediaHost,
             bypassController,
             statusBarStateController,
             notificationLockscreenUserManager,
             context,
-            configurationController
+            configurationController,
+            mediaFlags
         )
         keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
         keyguardMediaController.useSplitShade = false
@@ -150,4 +155,24 @@
         assertTrue("HostView wasn't attached to the single pane container",
             mediaContainerView.childCount == 1)
     }
+
+    @Test
+    fun testNotificationLayout_collapsedPlayer() {
+        verify(mediaHost).expansion = MediaHostState.COLLAPSED
+    }
+
+    @Test
+    fun testSessionLayout_expandedPlayer() {
+        whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+        keyguardMediaController = KeyguardMediaController(
+            mediaHost,
+            bypassController,
+            statusBarStateController,
+            notificationLockscreenUserManager,
+            context,
+            configurationController,
+            mediaFlags
+        )
+        verify(mediaHost).expansion = MediaHostState.EXPANDED
+    }
 }
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 5f800eb..cb05d03 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
@@ -16,24 +16,33 @@
 
 package com.android.systemui.media.taptotransfer
 
-import android.content.ComponentName
+import android.app.StatusBarManager
+import android.content.Context
+import android.media.MediaRoute2Info
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
-import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
+import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast
+import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast
+import com.android.systemui.media.taptotransfer.sender.TransferFailed
+import com.android.systemui.media.taptotransfer.sender.TransferToReceiverTriggered
+import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceSucceeded
+import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceTriggered
+import com.android.systemui.media.taptotransfer.sender.TransferToReceiverSucceeded
 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.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.nullable
+import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Ignore
 import org.junit.Test
 import org.mockito.Mock
-import org.mockito.Mockito.anyString
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 import java.io.PrintWriter
 import java.io.StringWriter
@@ -50,16 +59,17 @@
     private lateinit var mediaTttCommandLineHelper: MediaTttCommandLineHelper
 
     @Mock
-    private lateinit var mediaTttChipControllerReceiver: MediaTttChipControllerReceiver
+    private lateinit var statusBarManager: StatusBarManager
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        context.addMockSystemService(Context.STATUS_BAR_SERVICE, statusBarManager)
         mediaTttCommandLineHelper =
             MediaTttCommandLineHelper(
                 commandRegistry,
                 context,
-                mediaTttChipControllerReceiver,
+                FakeExecutor(FakeSystemClock()),
             )
     }
 
@@ -71,177 +81,147 @@
     }
 
     @Test(expected = IllegalStateException::class)
-    fun constructor_addReceiverCommandAlreadyRegistered() {
-        // Since creating the chip controller should automatically register the add command, it
+    fun constructor_receiverCommandAlreadyRegistered() {
+        // Since creating the chip controller should automatically register the receiver command, it
         // should throw when registering it again.
-        commandRegistry.registerCommand(
-            ADD_CHIP_COMMAND_RECEIVER_TAG
-        ) { EmptyCommand() }
-    }
-
-    @Test(expected = IllegalStateException::class)
-    fun constructor_removeReceiverCommandAlreadyRegistered() {
-        // Since creating the chip controller should automatically register the remove command, it
-        // should throw when registering it again.
-        commandRegistry.registerCommand(
-            REMOVE_CHIP_COMMAND_RECEIVER_TAG
-        ) { EmptyCommand() }
-    }
-
-    /* TODO(b/216318437): Revive these tests using the new SystemApis.
-    @Test
-    fun sender_moveCloserToStartCast_serviceCallbackCalled() {
-        commandRegistry.onShellCommand(pw, getMoveCloserToStartCastCommand())
-
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
-
-        val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
-        verify(mediaSenderService).closeToReceiverToStartCast(any(), capture(deviceInfoCaptor))
-        assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+        commandRegistry.registerCommand(RECEIVER_COMMAND) { EmptyCommand() }
     }
 
     @Test
-    fun sender_moveCloserToEndCast_serviceCallbackCalled() {
-        commandRegistry.onShellCommand(pw, getMoveCloserToEndCastCommand())
+    fun sender_almostCloseToStartCast_serviceCallbackCalled() {
+        commandRegistry.onShellCommand(
+            pw, getSenderCommand(AlmostCloseToStartCast::class.simpleName!!)
+        )
 
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
+        val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+        verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST),
+            capture(routeInfoCaptor),
+            nullable(),
+            nullable())
+        assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+    }
 
-        val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
-        verify(mediaSenderService).closeToReceiverToEndCast(any(), capture(deviceInfoCaptor))
-        assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+    @Test
+    fun sender_almostCloseToEndCast_serviceCallbackCalled() {
+        commandRegistry.onShellCommand(
+            pw, getSenderCommand(AlmostCloseToEndCast::class.simpleName!!)
+        )
+
+        val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+        verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST),
+            capture(routeInfoCaptor),
+            nullable(),
+            nullable())
+        assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
     }
 
     @Test
     fun sender_transferToReceiverTriggered_chipDisplayWithCorrectState() {
-        commandRegistry.onShellCommand(pw, getTransferToReceiverTriggeredCommand())
+        commandRegistry.onShellCommand(
+            pw, getSenderCommand(TransferToReceiverTriggered::class.simpleName!!)
+        )
 
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
-
-        val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
-        verify(mediaSenderService).transferToReceiverTriggered(any(), capture(deviceInfoCaptor))
-        assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+        val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+        verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED),
+            capture(routeInfoCaptor),
+            nullable(),
+            nullable())
+        assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
     }
 
     @Test
     fun sender_transferToThisDeviceTriggered_chipDisplayWithCorrectState() {
-        commandRegistry.onShellCommand(pw, getTransferToThisDeviceTriggeredCommand())
+        commandRegistry.onShellCommand(
+            pw, getSenderCommand(TransferToThisDeviceTriggered::class.simpleName!!)
+        )
 
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
-        verify(mediaSenderService).transferToThisDeviceTriggered(any(), any())
+        verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED),
+            any(),
+            nullable(),
+            nullable())
     }
 
     @Test
     fun sender_transferToReceiverSucceeded_chipDisplayWithCorrectState() {
-        commandRegistry.onShellCommand(pw, getTransferToReceiverSucceededCommand())
+        commandRegistry.onShellCommand(
+            pw, getSenderCommand(TransferToReceiverSucceeded::class.simpleName!!)
+        )
 
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
-
-        val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
-        verify(mediaSenderService)
-            .transferToReceiverSucceeded(any(), capture(deviceInfoCaptor), any())
-        assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+        val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+        verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED),
+            capture(routeInfoCaptor),
+            nullable(),
+            nullable())
+        assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
     }
 
     @Test
     fun sender_transferToThisDeviceSucceeded_chipDisplayWithCorrectState() {
-        commandRegistry.onShellCommand(pw, getTransferToThisDeviceSucceededCommand())
+        commandRegistry.onShellCommand(
+            pw, getSenderCommand(TransferToThisDeviceSucceeded::class.simpleName!!)
+        )
 
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
-
-        val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
-        verify(mediaSenderService)
-            .transferToThisDeviceSucceeded(any(), capture(deviceInfoCaptor), any())
-        assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+        val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+        verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED),
+            capture(routeInfoCaptor),
+            nullable(),
+            nullable())
+        assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
     }
 
     @Test
     fun sender_transferFailed_serviceCallbackCalled() {
-        commandRegistry.onShellCommand(pw, getTransferFailedCommand())
+        commandRegistry.onShellCommand(pw, getSenderCommand(TransferFailed::class.simpleName!!))
 
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
-        verify(mediaSenderService).transferFailed(any(), any())
+        verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED),
+            any(),
+            nullable(),
+            nullable())
     }
 
     @Test
-    fun sender_noLongerCloseToReceiver_serviceCallbackCalledAndServiceUnbound() {
-        commandRegistry.onShellCommand(pw, getNoLongerCloseToReceiverCommand())
+    fun sender_farFromReceiver_serviceCallbackCalled() {
+        commandRegistry.onShellCommand(pw, getSenderCommand(FAR_FROM_RECEIVER_STATE))
 
-        // Once we're no longer close to the receiver, we should unbind the service.
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isFalse()
-        verify(mediaSenderService).noLongerCloseToReceiver(any(), any())
-    }
-
-     */
-
-    @Test
-    fun receiver_addCommand_chipAdded() {
-        commandRegistry.onShellCommand(pw, arrayOf(ADD_CHIP_COMMAND_RECEIVER_TAG))
-
-        verify(mediaTttChipControllerReceiver).displayChip(any(ChipStateReceiver::class.java))
+        verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER),
+            any(),
+            nullable(),
+            nullable())
     }
 
     @Test
-    fun receiver_removeCommand_chipRemoved() {
-        commandRegistry.onShellCommand(pw, arrayOf(REMOVE_CHIP_COMMAND_RECEIVER_TAG))
+    fun receiver_closeToSender_serviceCallbackCalled() {
+        commandRegistry.onShellCommand(pw, getReceiverCommand(CLOSE_TO_SENDER_STATE))
 
-        verify(mediaTttChipControllerReceiver).removeChip()
+        verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER),
+            any()
+        )
     }
 
-    private fun getMoveCloserToStartCastCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            MOVE_CLOSER_TO_START_CAST_COMMAND_NAME
-        )
+    @Test
+    fun receiver_farFromSender_serviceCallbackCalled() {
+        commandRegistry.onShellCommand(pw, getReceiverCommand(FAR_FROM_SENDER_STATE))
 
-    private fun getMoveCloserToEndCastCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            MOVE_CLOSER_TO_END_CAST_COMMAND_NAME
+        verify(statusBarManager).updateMediaTapToTransferReceiverDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER),
+            any()
         )
+    }
 
-    private fun getTransferToReceiverTriggeredCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME
-        )
+    private fun getSenderCommand(displayState: String): Array<String> =
+        arrayOf(SENDER_COMMAND, DEVICE_NAME, displayState)
 
-    private fun getTransferToThisDeviceTriggeredCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME
-        )
-
-    private fun getTransferToReceiverSucceededCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            TRANSFER_TO_RECEIVER_SUCCEEDED_COMMAND_NAME
-        )
-
-    private fun getTransferToThisDeviceSucceededCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            TRANSFER_TO_THIS_DEVICE_SUCCEEDED_COMMAND_NAME
-        )
-
-    private fun getTransferFailedCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            TRANSFER_FAILED_COMMAND_NAME
-        )
-
-    private fun getNoLongerCloseToReceiverCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            NO_LONGER_CLOSE_TO_RECEIVER_COMMAND_NAME
-        )
+    private fun getReceiverCommand(displayState: String): Array<String> =
+        arrayOf(RECEIVER_COMMAND, displayState)
 
     class EmptyCommand : Command {
         override fun execute(pw: PrintWriter, args: List<String>) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 1d1265b1..fce4954 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -16,7 +16,9 @@
 
 package com.android.systemui.media.taptotransfer.receiver
 
+import android.app.StatusBarManager
 import android.graphics.drawable.Icon
+import android.media.MediaRoute2Info
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
@@ -24,6 +26,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.util.mockito.any
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -31,7 +34,8 @@
 import org.junit.Test
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
-import org.mockito.Mockito
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -41,11 +45,55 @@
 
     @Mock
     private lateinit var windowManager: WindowManager
+    @Mock
+    private lateinit var commandQueue: CommandQueue
+    private lateinit var commandQueueCallback: CommandQueue.Callbacks
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        controllerReceiver = MediaTttChipControllerReceiver(context, windowManager)
+        controllerReceiver = MediaTttChipControllerReceiver(commandQueue, context, windowManager)
+
+        val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
+        verify(commandQueue).addCallback(callbackCaptor.capture())
+        commandQueueCallback = callbackCaptor.value!!
+    }
+
+    @Test
+    fun commandQueueCallback_closeToSender_triggersChip() {
+        commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
+            StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
+            routeInfo
+        )
+
+        assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(ROUTE_NAME)
+    }
+
+    @Test
+    fun commandQueueCallback_farFromSender_noChipShown() {
+        commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
+            StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
+            routeInfo
+        )
+
+        verify(windowManager, never()).addView(any(), any())
+    }
+
+    @Test
+    fun commandQueueCallback_closeThenFar_chipShownThenHidden() {
+        commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
+            StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_CLOSE_TO_SENDER,
+            routeInfo
+        )
+
+        commandQueueCallback.updateMediaTapToTransferReceiverDisplay(
+            StatusBarManager.MEDIA_TRANSFER_RECEIVER_STATE_FAR_FROM_SENDER,
+            routeInfo
+        )
+
+        val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+        verify(windowManager).addView(viewCaptor.capture(), any())
+        verify(windowManager).removeView(viewCaptor.value)
     }
 
     @Test
@@ -61,9 +109,14 @@
 
     private fun getChipView(): ViewGroup {
         val viewCaptor = ArgumentCaptor.forClass(View::class.java)
-        Mockito.verify(windowManager).addView(viewCaptor.capture(), any())
+        verify(windowManager).addView(viewCaptor.capture(), any())
         return viewCaptor.value as ViewGroup
     }
 
     private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
 }
+
+private const val ROUTE_NAME = "Test name"
+private val routeInfo = MediaRoute2Info.Builder("id", ROUTE_NAME)
+    .addFeature("feature")
+    .build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index 58f4818..c74ac64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -16,8 +16,10 @@
 
 package com.android.systemui.media.taptotransfer.sender
 
+import android.app.StatusBarManager
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.Icon
+import android.media.MediaRoute2Info
 import android.view.View
 import android.view.WindowManager
 import android.widget.ImageView
@@ -35,6 +37,7 @@
 import org.junit.Test
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
@@ -49,17 +52,148 @@
     private lateinit var windowManager: WindowManager
     @Mock
     private lateinit var commandQueue: CommandQueue
+    private lateinit var commandQueueCallback: CommandQueue.Callbacks
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         appIconDrawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
-        controllerSender = MediaTttChipControllerSender(context, windowManager, commandQueue)
+        controllerSender = MediaTttChipControllerSender(commandQueue, context, windowManager)
+
+        val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
+        verify(commandQueue).addCallback(callbackCaptor.capture())
+        commandQueueCallback = callbackCaptor.value!!
     }
 
     @Test
-    fun moveCloserToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
-        val state = moveCloserToStartCast()
+    fun commandQueueCallback_almostCloseToStartCast_triggersCorrectChip() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+            routeInfo,
+            null
+        )
+
+        assertThat(getChipView().getChipText())
+            .isEqualTo(almostCloseToStartCast().getChipTextString(context))
+    }
+
+    @Test
+    fun commandQueueCallback_almostCloseToEndCast_triggersCorrectChip() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+            routeInfo,
+            null
+        )
+
+        assertThat(getChipView().getChipText())
+            .isEqualTo(almostCloseToEndCast().getChipTextString(context))
+    }
+
+    @Test
+    fun commandQueueCallback_transferToReceiverTriggered_triggersCorrectChip() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
+            routeInfo,
+            null
+        )
+
+        assertThat(getChipView().getChipText())
+            .isEqualTo(transferToReceiverTriggered().getChipTextString(context))
+    }
+
+    @Test
+    fun commandQueueCallback_transferToThisDeviceTriggered_triggersCorrectChip() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+            routeInfo,
+            null
+        )
+
+        assertThat(getChipView().getChipText())
+            .isEqualTo(transferToThisDeviceTriggered().getChipTextString(context))
+    }
+
+    @Test
+    fun commandQueueCallback_transferToReceiverSucceeded_triggersCorrectChip() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
+            routeInfo,
+            null
+        )
+
+        assertThat(getChipView().getChipText())
+            .isEqualTo(transferToReceiverSucceeded().getChipTextString(context))
+    }
+
+    @Test
+    fun commandQueueCallback_transferToThisDeviceSucceeded_triggersCorrectChip() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
+            routeInfo,
+            null
+        )
+
+        assertThat(getChipView().getChipText())
+            .isEqualTo(transferToThisDeviceSucceeded().getChipTextString(context))
+    }
+
+    @Test
+    fun commandQueueCallback_transferToReceiverFailed_triggersCorrectChip() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
+            routeInfo,
+            null
+        )
+
+        assertThat(getChipView().getChipText())
+            .isEqualTo(transferFailed().getChipTextString(context))
+    }
+
+    @Test
+    fun commandQueueCallback_transferToThisDeviceFailed_triggersCorrectChip() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED,
+            routeInfo,
+            null
+        )
+
+        assertThat(getChipView().getChipText())
+            .isEqualTo(transferFailed().getChipTextString(context))
+    }
+
+    @Test
+    fun commandQueueCallback_farFromReceiver_noChipShown() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+            routeInfo,
+            null
+        )
+
+        verify(windowManager, never()).addView(any(), any())
+    }
+
+    @Test
+    fun commandQueueCallback_almostCloseThenFarFromReceiver_chipShownThenHidden() {
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+            routeInfo,
+            null
+        )
+
+        commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+            StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+            routeInfo,
+            null
+        )
+
+        val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+        verify(windowManager).addView(viewCaptor.capture(), any())
+        verify(windowManager).removeView(viewCaptor.value)
+    }
+
+    @Test
+    fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
+        val state = almostCloseToStartCast()
         controllerSender.displayChip(state)
 
         val chipView = getChipView()
@@ -72,8 +206,8 @@
     }
 
     @Test
-    fun moveCloserToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
-        val state = moveCloserToEndCast()
+    fun almostCloseToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
+        val state = almostCloseToEndCast()
         controllerSender.displayChip(state)
 
         val chipView = getChipView()
@@ -250,8 +384,8 @@
     }
 
     @Test
-    fun changeFromCloserToStartToTransferTriggered_loadingIconAppears() {
-        controllerSender.displayChip(moveCloserToStartCast())
+    fun changeFromAlmostCloseToStartToTransferTriggered_loadingIconAppears() {
+        controllerSender.displayChip(almostCloseToStartCast())
         controllerSender.displayChip(transferToReceiverTriggered())
 
         assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
@@ -280,9 +414,9 @@
     }
 
     @Test
-    fun changeFromTransferSucceededToMoveCloserToStart_undoButtonDisappears() {
+    fun changeFromTransferSucceededToAlmostCloseToStart_undoButtonDisappears() {
         controllerSender.displayChip(transferToReceiverSucceeded())
-        controllerSender.displayChip(moveCloserToStartCast())
+        controllerSender.displayChip(almostCloseToStartCast())
 
         assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
     }
@@ -314,12 +448,12 @@
     }
 
     /** Helper method providing default parameters to not clutter up the tests. */
-    private fun moveCloserToStartCast() =
-        MoveCloserToStartCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+    private fun almostCloseToStartCast() =
+        AlmostCloseToStartCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
 
     /** Helper method providing default parameters to not clutter up the tests. */
-    private fun moveCloserToEndCast() =
-        MoveCloserToEndCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+    private fun almostCloseToEndCast() =
+        AlmostCloseToEndCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
 
     /** Helper method providing default parameters to not clutter up the tests. */
     private fun transferToReceiverTriggered() =
@@ -347,3 +481,7 @@
 
 private const val DEVICE_NAME = "My Tablet"
 private const val APP_ICON_CONTENT_DESC = "Content description"
+
+private val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
+    .addFeature("feature")
+    .build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
index a445d6f..3a95ed3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
@@ -31,6 +31,8 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.recents.OverviewProxyService;
@@ -55,10 +57,12 @@
     @Mock
     AccessibilityManager mAccessibilityManager;
     @Mock
-    AccessibilityManagerWrapper mAccessibilityManagerWrapper;
-    @Mock
     AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
     @Mock
+    AccessibilityButtonTargetsObserver mAccessibilityButtonTargetObserver;
+    @Mock
+    SystemActions mSystemActions;
+    @Mock
     OverviewProxyService mOverviewProxyService;
     @Mock
     Lazy<AssistManager> mAssistManagerLazy;
@@ -85,8 +89,9 @@
         when(mUserTracker.getUserId()).thenReturn(1);
 
         mNavBarHelper = new NavBarHelper(mContext, mAccessibilityManager,
-                mAccessibilityManagerWrapper, mAccessibilityButtonModeObserver,
-                mOverviewProxyService, mAssistManagerLazy, () -> Optional.of(mock(StatusBar.class)),
+                mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver,
+                mSystemActions, mOverviewProxyService, mAssistManagerLazy,
+                () -> Optional.of(mock(StatusBar.class)),
                 mNavigationModeController, mUserTracker, mDumpManager);
 
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 9ca898b..090ce43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -18,6 +18,7 @@
 
 import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
 import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN;
 import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
 import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
 import static android.inputmethodservice.InputMethodService.IME_VISIBLE;
@@ -73,6 +74,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestableContext;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
+import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -120,6 +122,8 @@
 
     private SysuiTestableContext mSysuiTestableContextExternal;
     @Mock
+    private SystemActions mSystemActions;
+    @Mock
     private OverviewProxyService mOverviewProxyService;
     @Mock
     private StatusBarStateController mStatusBarStateController;
@@ -182,8 +186,9 @@
         mDependency.injectTestDependency(NavigationModeController.class, mNavigationModeController);
         TestableLooper.get(this).runWithLooper(() -> {
             mNavBarHelper = spy(new NavBarHelper(mContext, mock(AccessibilityManager.class),
-                    mock(AccessibilityManagerWrapper.class),
-                    mock(AccessibilityButtonModeObserver.class), mOverviewProxyService,
+                    mock(AccessibilityButtonModeObserver.class),
+                    mock(AccessibilityButtonTargetsObserver.class),
+                    mSystemActions, mOverviewProxyService,
                     () -> mock(AssistManager.class), () -> Optional.of(mStatusBar),
                     mock(NavigationModeController.class), mock(UserTracker.class),
                     mock(DumpManager.class)));
@@ -285,20 +290,26 @@
                 BACK_DISPOSITION_DEFAULT, true);
 
         // Verify IME window state will be updated in default NavBar & external NavBar state reset.
-        assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
+        assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN
+                        | NAVIGATION_HINT_IME_SWITCHER_SHOWN,
                 defaultNavBar.getNavigationIconHints());
         assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
         assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+        assertFalse((externalNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN)
+                != 0);
 
         externalNavBar.setImeWindowStatus(EXTERNAL_DISPLAY_ID, null, IME_VISIBLE,
                 BACK_DISPOSITION_DEFAULT, true);
         defaultNavBar.setImeWindowStatus(
                 DEFAULT_DISPLAY, null, IME_INVISIBLE, BACK_DISPOSITION_DEFAULT, false);
         // Verify IME window state will be updated in external NavBar & default NavBar state reset.
-        assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN,
+        assertEquals(NAVIGATION_HINT_BACK_ALT | NAVIGATION_HINT_IME_SHOWN
+                        | NAVIGATION_HINT_IME_SWITCHER_SHOWN,
                 externalNavBar.getNavigationIconHints());
         assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
         assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+        assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN)
+                != 0);
     }
 
     @Test
@@ -316,6 +327,8 @@
                 BACK_DISPOSITION_DEFAULT, true);
         assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
         assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+        assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN)
+                != 0);
 
         // Verify navbar didn't alter and showing back icon when the keyguard is showing without
         // requesting IME insets visible.
@@ -324,6 +337,8 @@
                 BACK_DISPOSITION_DEFAULT, true);
         assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
         assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+        assertFalse((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN)
+                != 0);
 
         // Verify navbar altered and showing back icon when the keyguard is showing and
         // requesting IME insets visible.
@@ -333,6 +348,8 @@
                 BACK_DISPOSITION_DEFAULT, true);
         assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_BACK_ALT) != 0);
         assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0);
+        assertTrue((mNavigationBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SWITCHER_SHOWN)
+                != 0);
     }
 
     @Test
@@ -346,7 +363,7 @@
                 NavBarHelper.NavbarTaskbarStateUpdater.class));
 
         // Should be safe even though the internal view is now null.
-        mNavigationBar.updateAcessibilityStateFlags();
+        mNavigationBar.updateAccessibilityStateFlags();
     }
 
     private NavigationBar createNavBar(Context context) {
@@ -372,12 +389,10 @@
                 mock(ShadeController.class),
                 mock(NotificationRemoteInputManager.class),
                 mock(NotificationShadeDepthController.class),
-                mock(SystemActions.class),
                 mHandler,
                 mock(NavigationBarOverlayController.class),
                 mUiEventLogger,
                 mNavBarHelper,
-                mock(UserTracker.class),
                 mLightBarController,
                 mLightBarcontrollerFactory,
                 mAutoHideController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 8b353d9..3266d6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -47,6 +47,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.dagger.QSFragmentComponent;
 import com.android.systemui.qs.external.CustomTileStatePersister;
+import com.android.systemui.qs.external.TileLifecycleManager;
 import com.android.systemui.qs.external.TileServiceRequestController;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
@@ -136,6 +137,7 @@
         QSFragment qs = (QSFragment) mFragment;
         mFragments.dispatchResume();
         processAllMessages();
+
         QSTileHost host = new QSTileHost(mContext, mock(StatusBarIconController.class),
                 mock(QSFactoryImpl.class), new Handler(), Looper.myLooper(),
                 mock(PluginManager.class), mock(TunerService.class),
@@ -143,7 +145,7 @@
                 mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
                 mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
                 mock(SecureSettings.class), mock(CustomTileStatePersister.class),
-                mTileServiceRequestControllerBuilder);
+                mTileServiceRequestControllerBuilder, mock(TileLifecycleManager.Factory.class));
         qs.setHost(host);
 
         qs.setListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 1e651be..8872e28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -34,6 +34,7 @@
 import android.content.Intent;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -50,13 +51,13 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.qs.external.CustomTileStatePersister;
+import com.android.systemui.qs.external.TileLifecycleManager;
 import com.android.systemui.qs.external.TileServiceKey;
 import com.android.systemui.qs.external.TileServiceRequestController;
 import com.android.systemui.qs.logging.QSLogger;
@@ -127,6 +128,10 @@
     private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder;
     @Mock
     private TileServiceRequestController mTileServiceRequestController;
+    @Mock
+    private TileLifecycleManager.Factory mTileLifecycleManagerFactory;
+    @Mock
+    private TileLifecycleManager mTileLifecycleManager;
 
     private Handler mHandler;
     private TestableLooper mLooper;
@@ -139,6 +144,8 @@
         mHandler = new Handler(mLooper.getLooper());
         when(mTileServiceRequestControllerBuilder.create(any()))
                 .thenReturn(mTileServiceRequestController);
+        when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class)))
+                .thenReturn(mTileLifecycleManager);
 
         mSecureSettings = new FakeSettings();
         mSecureSettings.putStringForUser(
@@ -146,7 +153,8 @@
         mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
                 mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
                 mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
-                mSecureSettings, mCustomTileStatePersister, mTileServiceRequestControllerBuilder);
+                mSecureSettings, mCustomTileStatePersister, mTileServiceRequestControllerBuilder,
+                mTileLifecycleManagerFactory);
         setUpTileFactory();
     }
 
@@ -432,11 +440,13 @@
                 BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
                 UiEventLogger uiEventLogger, UserTracker userTracker,
                 SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister,
-                TileServiceRequestController.Builder tileServiceRequestControllerBuilder) {
+                TileServiceRequestController.Builder tileServiceRequestControllerBuilder,
+                TileLifecycleManager.Factory tileLifecycleManagerFactory) {
             super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
                     tunerService, autoTiles, dumpManager, broadcastDispatcher,
                     Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings,
-                    customTileStatePersister, tileServiceRequestControllerBuilder);
+                    customTileStatePersister, tileServiceRequestControllerBuilder,
+                    tileLifecycleManagerFactory);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 09c6d9e..1eb16fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -23,11 +23,14 @@
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.MediaFlags
 import com.android.systemui.media.MediaHost
+import com.android.systemui.media.MediaHostState
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.plugins.qs.QSTileView
 import com.android.systemui.qs.customize.QSCustomizerController
 import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.util.leak.RotationUtils
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
@@ -55,6 +58,8 @@
     @Mock
     private lateinit var mediaHost: MediaHost
     @Mock
+    private lateinit var mediaFlags: MediaFlags
+    @Mock
     private lateinit var metricsLogger: MetricsLogger
     private val uiEventLogger = UiEventLoggerFake()
     @Mock
@@ -71,7 +76,7 @@
     @Captor
     private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener>
 
-    private lateinit var controller: QuickQSPanelController
+    private lateinit var controller: TestQuickQSPanelController
 
     @Before
     fun setUp() {
@@ -82,13 +87,16 @@
         `when`(quickQSPanel.dumpableTag).thenReturn("")
         `when`(quickQSPanel.resources).thenReturn(mContext.resources)
         `when`(qsTileHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView)
+        `when`(mediaFlags.useMediaSessionLayout()).thenReturn(false)
 
-        controller = QuickQSPanelController(
+        controller = TestQuickQSPanelController(
                 quickQSPanel,
                 qsTileHost,
                 qsCustomizerController,
                 false,
                 mediaHost,
+                true,
+                mediaFlags,
                 metricsLogger,
                 uiEventLogger,
                 qsLogger,
@@ -133,4 +141,49 @@
 
         verify(quickQsBrightnessController).refreshVisibility(anyBoolean())
     }
+
+    @Test
+    fun testMediaExpansionUpdatedWhenConfigurationChanged() {
+        `when`(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+
+        // times(2) because both controller and base controller are registering their listeners
+        verify(quickQSPanel, times(2)).addOnConfigurationChangedListener(captor.capture())
+
+        captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
+        verify(mediaHost).expansion = MediaHostState.EXPANDED
+
+        // Rotate device, verify media size updated
+        controller.setRotation(RotationUtils.ROTATION_LANDSCAPE)
+        captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
+
+        // times(2) because init will have set to collapsed because the flag was off
+        verify(mediaHost, times(2)).expansion = MediaHostState.COLLAPSED
+    }
+
+    class TestQuickQSPanelController(
+        view: QuickQSPanel,
+        qsTileHost: QSTileHost,
+        qsCustomizerController: QSCustomizerController,
+        usingMediaPlayer: Boolean,
+        mediaHost: MediaHost,
+        usingCollapsedLandscapeMedia: Boolean,
+        mediaFlags: MediaFlags,
+        metricsLogger: MetricsLogger,
+        uiEventLogger: UiEventLoggerFake,
+        qsLogger: QSLogger,
+        dumpManager: DumpManager,
+        quickQSBrightnessController: QuickQSBrightnessController
+    ) : QuickQSPanelController(view, qsTileHost, qsCustomizerController, usingMediaPlayer,
+        mediaHost, usingCollapsedLandscapeMedia, mediaFlags, metricsLogger, uiEventLogger, qsLogger,
+        dumpManager, quickQSBrightnessController) {
+
+        private var rotation = RotationUtils.ROTATION_NONE
+
+        @Override
+        override fun getRotation(): Int = rotation
+
+        fun setRotation(newRotation: Int) {
+            rotation = newRotation
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 97ad8bc..f3fcdbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -92,7 +92,6 @@
 
         mContext.addMockSystemService("window", windowService)
         mContext.setMockPackageManager(packageManager)
-        `when`(tileHost.tileServices).thenReturn(tileServices)
         `when`(tileHost.context).thenReturn(mContext)
         `when`(tileServices.getTileWrapper(any(CustomTile::class.java)))
                 .thenReturn(tileServiceManager)
@@ -113,7 +112,8 @@
                 statusBarStateController,
                 activityStarter,
                 qsLogger,
-                customTileStatePersister
+                customTileStatePersister,
+                tileServices
         )
 
         customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index f2303c2..b559d18 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -43,7 +43,6 @@
 import android.os.UserHandle;
 import android.service.quicksettings.IQSService;
 import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -96,11 +95,11 @@
         mThread.start();
         mHandler = Handler.createAsync(mThread.getLooper());
         mStateManager = new TileLifecycleManager(mHandler, mWrappedContext,
-                Mockito.mock(IQSService.class), new Tile(),
-                mTileServiceIntent,
-                mUser,
+                Mockito.mock(IQSService.class),
                 mMockPackageManagerAdapter,
-                mMockBroadcastDispatcher);
+                mMockBroadcastDispatcher,
+                mTileServiceIntent,
+                mUser);
     }
 
     @After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index d604b2c..e39d6a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -34,7 +34,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
-import android.service.quicksettings.Tile;
 import android.service.quicksettings.TileService;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -54,6 +53,7 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -104,6 +104,12 @@
     private TileServiceRequestController.Builder mTileServiceRequestControllerBuilder;
     @Mock
     private TileServiceRequestController mTileServiceRequestController;
+    @Mock
+    private KeyguardStateController mKeyguardStateController;
+    @Mock
+    private TileLifecycleManager.Factory mTileLifecycleManagerFactory;
+    @Mock
+    private TileLifecycleManager mTileLifecycleManager;
 
     @Before
     public void setUp() throws Exception {
@@ -113,6 +119,8 @@
 
         when(mTileServiceRequestControllerBuilder.create(any()))
                 .thenReturn(mTileServiceRequestController);
+        when(mTileLifecycleManagerFactory.create(any(Intent.class), any(UserHandle.class)))
+                .thenReturn(mTileLifecycleManager);
 
         QSTileHost host = new QSTileHost(mContext,
                 mStatusBarIconController,
@@ -130,14 +138,16 @@
                 mUserTracker,
                 mSecureSettings,
                 mock(CustomTileStatePersister.class),
-                mTileServiceRequestControllerBuilder);
+                mTileServiceRequestControllerBuilder,
+                mTileLifecycleManagerFactory);
         mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
-                mUserTracker);
+                mUserTracker, mKeyguardStateController);
     }
 
     @After
     public void tearDown() throws Exception {
         mTileService.getHost().destroy();
+        mTileService.destroy();
         TestableLooper.get(this).processAllMessages();
     }
 
@@ -217,13 +227,14 @@
 
     private class TestTileServices extends TileServices {
         TestTileServices(QSTileHost host, Looper looper,
-                BroadcastDispatcher broadcastDispatcher, UserTracker userTracker) {
-            super(host, looper, broadcastDispatcher, userTracker);
+                BroadcastDispatcher broadcastDispatcher, UserTracker userTracker,
+                KeyguardStateController keyguardStateController) {
+            super(host, looper, broadcastDispatcher, userTracker, keyguardStateController);
         }
 
         @Override
-        protected TileServiceManager onCreateTileService(ComponentName component, Tile qsTile,
-                BroadcastDispatcher broadcastDispatcher) {
+        protected TileServiceManager onCreateTileService(
+                ComponentName component, BroadcastDispatcher broadcastDispatcher) {
             TileServiceManager manager = mock(TileServiceManager.class);
             mManagers.add(manager);
             when(manager.isLifecycleStarted()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java
deleted file mode 100644
index 6059afe..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * 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.systemui.statusbar;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.IActivityManager;
-import android.app.IForegroundServiceObserver;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
-import android.util.Pair;
-
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.test.filters.MediumTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.policy.RunningFgsController;
-import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime;
-import com.android.systemui.statusbar.policy.RunningFgsControllerImpl;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Random;
-import java.util.function.Consumer;
-
-@MediumTest
-@RunWith(AndroidTestingRunner.class)
-public class RunningFgsControllerTest extends SysuiTestCase {
-
-    private RunningFgsController mController;
-
-    private FakeSystemClock mSystemClock = new FakeSystemClock();
-    private FakeExecutor mExecutor = new FakeExecutor(mSystemClock);
-    private TestCallback mCallback = new TestCallback();
-
-    @Mock
-    private IActivityManager mActivityManager;
-    @Mock
-    private Lifecycle mLifecycle;
-    @Mock
-    private LifecycleOwner mLifecycleOwner;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycle);
-        mController = new RunningFgsControllerImpl(mExecutor, mSystemClock, mActivityManager);
-    }
-
-    @Test
-    public void testInitRegistersListenerInImpl() throws RemoteException {
-        ((RunningFgsControllerImpl) mController).init();
-        verify(mActivityManager, times(1)).registerForegroundServiceObserver(any());
-    }
-
-    @Test
-    public void testAddCallbackCallsInitInImpl() {
-        verifyInitIsCalled(controller -> controller.addCallback(mCallback));
-    }
-
-    @Test
-    public void testRemoveCallbackCallsInitInImpl() {
-        verifyInitIsCalled(controller -> controller.removeCallback(mCallback));
-    }
-
-    @Test
-    public void testObserve1CallsInitInImpl() {
-        verifyInitIsCalled(controller -> controller.observe(mLifecycle, mCallback));
-    }
-
-    @Test
-    public void testObserve2CallsInitInImpl() {
-        verifyInitIsCalled(controller -> controller.observe(mLifecycleOwner, mCallback));
-    }
-
-    @Test
-    public void testGetPackagesWithFgsCallsInitInImpl() {
-        verifyInitIsCalled(controller -> controller.getPackagesWithFgs());
-    }
-
-    @Test
-    public void testStopFgsCallsInitInImpl() {
-        verifyInitIsCalled(controller -> controller.stopFgs(0, ""));
-    }
-
-    /**
-     * Tests that callbacks can be added
-     */
-    @Test
-    public void testAddCallback() throws RemoteException {
-        String testPackageName = "testPackageName";
-        int testUserId = 0;
-
-        IForegroundServiceObserver observer = prepareObserver();
-        mController.addCallback(mCallback);
-
-        observer.onForegroundStateChanged(new Binder(), testPackageName, testUserId, true);
-
-        mExecutor.advanceClockToLast();
-        mExecutor.runAllReady();
-
-        assertEquals("Callback should have been invoked exactly once.",
-                1, mCallback.mInvocations.size());
-
-        List<UserPackageTime> userPackageTimes = mCallback.mInvocations.get(0);
-        assertEquals("There should have only been one package in callback. packages="
-                        + userPackageTimes,
-                1, userPackageTimes.size());
-
-        UserPackageTime upt = userPackageTimes.get(0);
-        assertEquals(testPackageName, upt.getPackageName());
-        assertEquals(testUserId, upt.getUserId());
-    }
-
-    /**
-     * Tests that callbacks can be removed. This test is only meaningful if
-     * {@link #testAddCallback()} can pass.
-     */
-    @Test
-    public void testRemoveCallback() throws RemoteException {
-        String testPackageName = "testPackageName";
-        int testUserId = 0;
-
-        IForegroundServiceObserver observer = prepareObserver();
-        mController.addCallback(mCallback);
-        mController.removeCallback(mCallback);
-
-        observer.onForegroundStateChanged(new Binder(), testPackageName, testUserId, true);
-
-        mExecutor.advanceClockToLast();
-        mExecutor.runAllReady();
-
-        assertEquals("Callback should not have been invoked.",
-                0, mCallback.mInvocations.size());
-    }
-
-    /**
-     * Tests packages are added when the controller receives a callback from activity manager for
-     * a foreground service start.
-     */
-    @Test
-    public void testGetPackagesWithFgsAddingPackages() throws RemoteException {
-        int numPackages = 20;
-        int numUsers = 3;
-
-        IForegroundServiceObserver observer = prepareObserver();
-
-        assertEquals("List should be empty", 0, mController.getPackagesWithFgs().size());
-
-        List<Pair<Integer, String>> addedPackages = new ArrayList<>();
-        for (int pkgNumber = 0; pkgNumber < numPackages; pkgNumber++) {
-            for (int userId = 0; userId < numUsers; userId++) {
-                String packageName = "package.name." + pkgNumber;
-                addedPackages.add(new Pair(userId, packageName));
-
-                observer.onForegroundStateChanged(new Binder(), packageName, userId, true);
-
-                containsAllAddedPackages(addedPackages, mController.getPackagesWithFgs());
-            }
-        }
-    }
-
-    /**
-     * Tests packages are removed when the controller receives a callback from activity manager for
-     * a foreground service ending.
-     */
-    @Test
-    public void testGetPackagesWithFgsRemovingPackages() throws RemoteException {
-        int numPackages = 20;
-        int numUsers = 3;
-        int arrayLength = numPackages * numUsers;
-
-        String[] packages = new String[arrayLength];
-        int[] users = new int[arrayLength];
-        IBinder[] tokens = new IBinder[arrayLength];
-        for (int pkgNumber = 0; pkgNumber < numPackages; pkgNumber++) {
-            for (int userId = 0; userId < numUsers; userId++) {
-                int i = pkgNumber * numUsers + userId;
-                packages[i] =  "package.name." + pkgNumber;
-                users[i] = userId;
-                tokens[i] = new Binder();
-            }
-        }
-
-        IForegroundServiceObserver observer = prepareObserver();
-
-        for (int i = 0; i < packages.length; i++) {
-            observer.onForegroundStateChanged(tokens[i], packages[i], users[i], true);
-        }
-
-        assertEquals(packages.length, mController.getPackagesWithFgs().size());
-
-        List<Integer> removeOrder = new ArrayList<>();
-        for (int i = 0; i < packages.length; i++) {
-            removeOrder.add(i);
-        }
-        Collections.shuffle(removeOrder, new Random(12345));
-
-        for (int idx : removeOrder) {
-            removePackageAndAssertRemovedFromList(observer, tokens[idx], packages[idx], users[idx]);
-        }
-
-        assertEquals(0, mController.getPackagesWithFgs().size());
-    }
-
-    /**
-     * Tests a call on stopFgs forwards to activity manager.
-     */
-    @Test
-    public void testStopFgs() throws RemoteException {
-        String pkgName = "package.name";
-        mController.stopFgs(0, pkgName);
-        verify(mActivityManager).stopAppForUser(pkgName, 0);
-    }
-
-    /**
-     * Tests a package which starts multiple services is only listed once and is only removed once
-     * all services are stopped.
-     */
-    @Test
-    public void testSinglePackageWithMultipleServices() throws RemoteException {
-        String packageName = "package.name";
-        int userId = 0;
-        IBinder serviceToken1 = new Binder();
-        IBinder serviceToken2 = new Binder();
-
-        IForegroundServiceObserver observer = prepareObserver();
-
-        assertEquals(0, mController.getPackagesWithFgs().size());
-
-        observer.onForegroundStateChanged(serviceToken1, packageName, userId, true);
-        assertSinglePackage(packageName, userId);
-
-        observer.onForegroundStateChanged(serviceToken2, packageName, userId, true);
-        assertSinglePackage(packageName, userId);
-
-        observer.onForegroundStateChanged(serviceToken2, packageName, userId, false);
-        assertSinglePackage(packageName, userId);
-
-        observer.onForegroundStateChanged(serviceToken1, packageName, userId, false);
-        assertEquals(0, mController.getPackagesWithFgs().size());
-    }
-
-    private IForegroundServiceObserver prepareObserver()
-            throws RemoteException {
-        mController.getPackagesWithFgs();
-
-        ArgumentCaptor<IForegroundServiceObserver> argumentCaptor =
-                ArgumentCaptor.forClass(IForegroundServiceObserver.class);
-        verify(mActivityManager).registerForegroundServiceObserver(argumentCaptor.capture());
-
-        return argumentCaptor.getValue();
-    }
-
-    private void verifyInitIsCalled(Consumer<RunningFgsControllerImpl> c) {
-        RunningFgsControllerImpl spiedController = Mockito.spy(
-                ((RunningFgsControllerImpl) mController));
-        c.accept(spiedController);
-        verify(spiedController, atLeastOnce()).init();
-    }
-
-    private void containsAllAddedPackages(List<Pair<Integer, String>> addedPackages,
-            List<UserPackageTime> runningFgsPackages) {
-        for (Pair<Integer, String> userPkg : addedPackages) {
-            assertTrue(userPkg + " was not found in returned list",
-                    runningFgsPackages.stream().anyMatch(
-                            upt -> userPkg.first == upt.getUserId()
-                                    && Objects.equals(upt.getPackageName(), userPkg.second)));
-        }
-        for (UserPackageTime upt : runningFgsPackages) {
-            int userId = upt.getUserId();
-            String packageName = upt.getPackageName();
-            assertTrue("Unknown <user=" + userId + ", package=" + packageName + ">"
-                            + " in returned list",
-                    addedPackages.stream().anyMatch(userPkg -> userPkg.first == userId
-                            && Objects.equals(packageName, userPkg.second)));
-        }
-    }
-
-    private void removePackageAndAssertRemovedFromList(IForegroundServiceObserver observer,
-            IBinder token, String pkg, int userId) throws RemoteException {
-        observer.onForegroundStateChanged(token, pkg, userId, false);
-        List<UserPackageTime> packagesWithFgs = mController.getPackagesWithFgs();
-        assertFalse("Package \"" + pkg + "\" was not removed",
-                packagesWithFgs.stream().anyMatch(upt ->
-                        Objects.equals(upt.getPackageName(), pkg) && upt.getUserId() == userId));
-    }
-
-    private void assertSinglePackage(String packageName, int userId) {
-        assertEquals(1, mController.getPackagesWithFgs().size());
-        assertEquals(packageName, mController.getPackagesWithFgs().get(0).getPackageName());
-        assertEquals(userId, mController.getPackagesWithFgs().get(0).getUserId());
-    }
-
-    private static class TestCallback implements RunningFgsController.Callback {
-
-        private List<List<UserPackageTime>> mInvocations = new ArrayList<>();
-
-        @Override
-        public void onFgsPackagesChanged(List<UserPackageTime> packages) {
-            mInvocations.add(packages);
-        }
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 85ea52b..d13451d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
@@ -37,6 +39,7 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Icon;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
@@ -130,7 +133,12 @@
         Icon icon = Icon.createWithBitmap(largeBitmap);
         StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
                 icon, 0, 0, "");
-        assertFalse(mIconView.set(largeIcon));
+        assertTrue(mIconView.set(largeIcon));
+
+        // The view should downscale the bitmap.
+        BitmapDrawable drawable = (BitmapDrawable) mIconView.getDrawable();
+        assertThat(drawable.getBitmap().getWidth()).isLessThan(1000);
+        assertThat(drawable.getBitmap().getHeight()).isLessThan(1000);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
new file mode 100644
index 0000000..3820b98
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection
+
+import android.testing.AndroidTestingRunner
+import android.view.Choreographer
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.anyLong
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotifPipelineChoreographerTest : SysuiTestCase() {
+
+    val viewChoreographer: Choreographer = mock()
+    val timeoueSubscription: Runnable = mock()
+    val executor: DelayableExecutor = mock<DelayableExecutor>().also {
+        whenever(it.executeDelayed(any(), anyLong())).thenReturn(timeoueSubscription)
+    }
+
+    val pipelineChoreographer: NotifPipelineChoreographer = NotifPipelineChoreographerModule
+            .provideChoreographer(viewChoreographer, executor)
+
+    @Test
+    fun scheduleThenEvalFrameCallback() {
+        // GIVEN a registered eval listener and scheduled choreographer
+        var hasEvaluated = false
+        pipelineChoreographer.addOnEvalListener {
+            hasEvaluated = true
+        }
+        pipelineChoreographer.schedule()
+        val frameCallback: Choreographer.FrameCallback = withArgCaptor {
+            verify(viewChoreographer).postFrameCallback(capture())
+        }
+        // WHEN the choreographer would invoke its callback
+        frameCallback.doFrame(0)
+        // THEN the choreographer would evaluate, and the timeoutSubscription would have been
+        // cancelled
+        assertTrue(hasEvaluated)
+        verify(timeoueSubscription).run()
+    }
+
+    @Test
+    fun scheduleThenEvalTimeoutCallback() {
+        // GIVEN a registered eval listener and scheduled choreographer
+        var hasEvaluated = false
+        pipelineChoreographer.addOnEvalListener {
+            hasEvaluated = true
+        }
+        pipelineChoreographer.schedule()
+        val frameCallback: Choreographer.FrameCallback = withArgCaptor {
+            verify(viewChoreographer).postFrameCallback(capture())
+        }
+        val runnable: Runnable = withArgCaptor {
+            verify(executor).executeDelayed(capture(), anyLong())
+        }
+        // WHEN the executor would invoke its callback (indicating a timeout)
+        runnable.run()
+        // THEN the choreographer would evaluate, and the FrameCallback would have been unregistered
+        assertTrue(hasEvaluated)
+        verify(viewChoreographer).removeFrameCallback(frameCallback)
+    }
+
+    @Test
+    fun scheduleThenCancel() {
+        // GIVEN a scheduled choreographer
+        pipelineChoreographer.schedule()
+        val frameCallback: Choreographer.FrameCallback = withArgCaptor {
+            verify(viewChoreographer).postFrameCallback(capture())
+        }
+        // WHEN the scheduled run is cancelled
+        pipelineChoreographer.cancel()
+        // THEN both the FrameCallback is unregistered and the timeout subscription is cancelled.
+        verify(viewChoreographer).removeFrameCallback(frameCallback)
+        verify(timeoueSubscription).run()
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 8fb066b..f470715 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.inOrder;
@@ -46,6 +47,7 @@
 import android.util.ArrayMap;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -109,6 +111,8 @@
 
     @Captor private ArgumentCaptor<CollectionReadyForBuildListener> mBuildListenerCaptor;
 
+    private final FakeNotifPipelineChoreographer mPipelineChoreographer =
+            new FakeNotifPipelineChoreographer();
     private CollectionReadyForBuildListener mReadyForBuildListener;
     private List<NotificationEntryBuilder> mPendingSet = new ArrayList<>();
     private List<NotificationEntry> mEntrySet = new ArrayList<>();
@@ -125,11 +129,12 @@
         allowTestableLooperAsMainThread();
 
         mListBuilder = new ShadeListBuilder(
-                mSystemClock,
-                mNotifPipelineFlags,
-                mLogger,
                 mDumpManager,
-                mInteractionTracker
+                mPipelineChoreographer,
+                mNotifPipelineFlags,
+                mInteractionTracker,
+                mLogger,
+                mSystemClock
         );
         mListBuilder.setOnRenderListListener(mOnRenderListListener);
 
@@ -565,6 +570,7 @@
 
         // WHEN the pipeline is kicked off
         mReadyForBuildListener.onBuildList(singletonList(entry));
+        mPipelineChoreographer.runIfScheduled();
 
         // THEN the entry's initialization time is reset
         assertFalse(entry.hasFinishedInitialization());
@@ -872,6 +878,73 @@
     }
 
     @Test
+    public void testThatSectionComparatorsAreCalled() {
+        // GIVEN a section with a comparator that elevates some packages over others
+        NotifComparator comparator = spy(new HypeComparator(PACKAGE_2, PACKAGE_4));
+        NotifSectioner sectioner = new PackageSectioner(
+                List.of(PACKAGE_1, PACKAGE_2, PACKAGE_4, PACKAGE_5), comparator);
+        mListBuilder.setSectioners(List.of(sectioner));
+
+        // WHEN the pipeline is kicked off on a bunch of notifications
+        addNotif(0, PACKAGE_0);
+        addNotif(1, PACKAGE_1);
+        addNotif(2, PACKAGE_2);
+        addNotif(3, PACKAGE_3);
+        addNotif(4, PACKAGE_4);
+        addNotif(5, PACKAGE_5);
+        dispatchBuild();
+
+        // THEN the notifs are sorted according to both sectioning and the section's comparator
+        verifyBuiltList(
+                notif(2),
+                notif(4),
+                notif(1),
+                notif(5),
+                notif(0),
+                notif(3)
+        );
+
+        // VERIFY that the comparator is invoked at least 3 times
+        verify(comparator, atLeast(3)).compare(any(), any());
+
+        // VERIFY that the comparator is never invoked with the entry from package 0 or 3.
+        final NotificationEntry package0Entry = mEntrySet.get(0);
+        verify(comparator, never()).compare(eq(package0Entry), any());
+        verify(comparator, never()).compare(any(), eq(package0Entry));
+        final NotificationEntry package3Entry = mEntrySet.get(3);
+        verify(comparator, never()).compare(eq(package3Entry), any());
+        verify(comparator, never()).compare(any(), eq(package3Entry));
+    }
+
+    @Test
+    public void testThatSectionComparatorsAreNotCalledForSectionWithSingleEntry() {
+        // GIVEN a section with a comparator that will have only 1 element
+        NotifComparator comparator = spy(new HypeComparator(PACKAGE_3));
+        NotifSectioner sectioner = new PackageSectioner(List.of(PACKAGE_3), comparator);
+        mListBuilder.setSectioners(List.of(sectioner));
+
+        // WHEN the pipeline is kicked off on a bunch of notifications
+        addNotif(0, PACKAGE_1);
+        addNotif(1, PACKAGE_2);
+        addNotif(2, PACKAGE_3);
+        addNotif(3, PACKAGE_4);
+        addNotif(4, PACKAGE_5);
+        dispatchBuild();
+
+        // THEN the notifs are sorted according to the sectioning
+        verifyBuiltList(
+                notif(2),
+                notif(0),
+                notif(1),
+                notif(3),
+                notif(4)
+        );
+
+        // VERIFY that the comparator is never invoked
+        verify(comparator, never()).compare(any(), any());
+    }
+
+    @Test
     public void testListenersAndPluggablesAreFiredInOrder() {
         // GIVEN a bunch of registered listeners and pluggables
         NotifFilter preGroupFilter = spy(new PackageFilter(PACKAGE_1));
@@ -934,7 +1007,8 @@
         // GIVEN a variety of pluggables
         NotifFilter packageFilter = new PackageFilter(PACKAGE_1);
         NotifPromoter idPromoter = new IdPromoter(4);
-        NotifSectioner section = new PackageSectioner(PACKAGE_1);
+        NotifComparator sectionComparator = new HypeComparator(PACKAGE_1);
+        NotifSectioner section = new PackageSectioner(List.of(PACKAGE_1), sectionComparator);
         NotifComparator hypeComparator = new HypeComparator(PACKAGE_2);
         Invalidator preRenderInvalidator = new Invalidator("PreRenderInvalidator") {};
 
@@ -954,22 +1028,38 @@
 
         clearInvocations(mOnRenderListListener);
         packageFilter.invalidateList();
+        assertTrue(mPipelineChoreographer.isScheduled());
+        mPipelineChoreographer.runIfScheduled();
         verify(mOnRenderListListener).onRenderList(anyList());
 
         clearInvocations(mOnRenderListListener);
         idPromoter.invalidateList();
+        assertTrue(mPipelineChoreographer.isScheduled());
+        mPipelineChoreographer.runIfScheduled();
         verify(mOnRenderListListener).onRenderList(anyList());
 
         clearInvocations(mOnRenderListListener);
         section.invalidateList();
+        assertTrue(mPipelineChoreographer.isScheduled());
+        mPipelineChoreographer.runIfScheduled();
         verify(mOnRenderListListener).onRenderList(anyList());
 
         clearInvocations(mOnRenderListListener);
         hypeComparator.invalidateList();
+        assertTrue(mPipelineChoreographer.isScheduled());
+        mPipelineChoreographer.runIfScheduled();
+        verify(mOnRenderListListener).onRenderList(anyList());
+
+        clearInvocations(mOnRenderListListener);
+        sectionComparator.invalidateList();
+        assertTrue(mPipelineChoreographer.isScheduled());
+        mPipelineChoreographer.runIfScheduled();
         verify(mOnRenderListListener).onRenderList(anyList());
 
         clearInvocations(mOnRenderListListener);
         preRenderInvalidator.invalidateList();
+        assertTrue(mPipelineChoreographer.isScheduled());
+        mPipelineChoreographer.runIfScheduled();
         verify(mOnRenderListListener).onRenderList(anyList());
     }
 
@@ -1441,6 +1531,7 @@
         // WHEN visual stability manager allows group changes again
         mStabilityManager.setAllowGroupChanges(true);
         mStabilityManager.invalidateList();
+        mPipelineChoreographer.runIfScheduled();
 
         // THEN entries are grouped
         verifyBuiltList(
@@ -1479,6 +1570,7 @@
         // WHEN section changes are allowed again
         mStabilityManager.setAllowSectionChanges(true);
         mStabilityManager.invalidateList();
+        mPipelineChoreographer.runIfScheduled();
 
         // THEN the section updates
         assertEquals(newSectioner, mEntrySet.get(0).getSection().getSectioner());
@@ -1699,6 +1791,30 @@
     }
 
     @Test
+    public void testMultipleInvalidationsCoalesce() {
+        // GIVEN a PreGroupFilter and a FinalizeFilter
+        NotifFilter filter1 = new PackageFilter(PACKAGE_5);
+        NotifFilter filter2 = new PackageFilter(PACKAGE_0);
+        mListBuilder.addPreGroupFilter(filter1);
+        mListBuilder.addFinalizeFilter(filter2);
+
+        // WHEN both filters invalidate
+        filter1.invalidateList();
+        filter2.invalidateList();
+
+        // THEN the pipeline choreographer is scheduled to evaluate, AND the pipeline hasn't
+        // actually run.
+        assertTrue(mPipelineChoreographer.isScheduled());
+        verify(mOnRenderListListener, never()).onRenderList(anyList());
+
+        // WHEN the pipeline choreographer actually runs
+        mPipelineChoreographer.runIfScheduled();
+
+        // THEN the pipeline runs
+        verify(mOnRenderListListener).onRenderList(anyList());
+    }
+
+    @Test
     public void testIsSorted() {
         Comparator<Integer> intCmp = Integer::compare;
         assertTrue(ShadeListBuilder.isSorted(Collections.emptyList(), intCmp));
@@ -1840,6 +1956,7 @@
         }
 
         mReadyForBuildListener.onBuildList(mEntrySet);
+        mPipelineChoreographer.runIfScheduled();
     }
 
     private void verifyBuiltList(ExpectedEntry ...expectedEntries) {
@@ -2037,16 +2154,30 @@
 
     /** Represents a section for the passed pkg */
     private static class PackageSectioner extends NotifSectioner {
-        private final String mPackage;
+        private final List<String> mPackages;
+        private final NotifComparator mComparator;
+
+        PackageSectioner(List<String> pkgs, NotifComparator comparator) {
+            super("PackageSection_" + pkgs, 0);
+            mPackages = pkgs;
+            mComparator = comparator;
+        }
 
         PackageSectioner(String pkg) {
             super("PackageSection_" + pkg, 0);
-            mPackage = pkg;
+            mPackages = List.of(pkg);
+            mComparator = null;
+        }
+
+        @Nullable
+        @Override
+        public NotifComparator getComparator() {
+            return mComparator;
         }
 
         @Override
         public boolean isInSection(ListEntry entry) {
-            return entry.getRepresentativeEntry().getSbn().getPackageName().equals(mPackage);
+            return mPackages.contains(entry.getRepresentativeEntry().getSbn().getPackageName());
         }
     }
 
@@ -2157,6 +2288,7 @@
         }
     }
 
+    private static final String PACKAGE_0 = "com.test0";
     private static final String PACKAGE_1 = "com.test1";
     private static final String PACKAGE_2 = "com.test2";
     private static final String PACKAGE_3 = "org.test3";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index 8deac94..7692a05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -32,7 +32,6 @@
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
-import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
 import org.junit.Assert.assertFalse
@@ -41,7 +40,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
@@ -79,7 +77,7 @@
         }
 
         peopleSectioner = coordinator.sectioner
-        peopleComparator = coordinator.comparator
+        peopleComparator = peopleSectioner.comparator!!
 
         entry = NotificationEntryBuilder().setChannel(channel).build()
 
@@ -108,16 +106,6 @@
     }
 
     @Test
-    fun testComparatorIgnoresFromOtherSection() {
-        val e1 = NotificationEntryBuilder().setId(1).setChannel(channel).build()
-        val e2 = NotificationEntryBuilder().setId(2).setChannel(channel).build()
-
-        // wrong section -- never classify
-        assertThat(peopleComparator.compare(e1, e2)).isEqualTo(0)
-        verify(peopleNotificationIdentifier, never()).getPeopleNotificationType(any())
-    }
-
-    @Test
     fun testComparatorPutsImportantPeopleFirst() {
         whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryA))
             .thenReturn(TYPE_IMPORTANT_PERSON)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index a890414..52189e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -48,6 +48,7 @@
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.MediaFeatureFlag;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -273,6 +274,7 @@
                                 null,
                                 new FalsingManagerFake(),
                                 new FalsingCollectorFake(),
+                                mock(FeatureFlags.class),
                                 mPeopleNotificationIdentifier,
                                 Optional.of(mock(BubblesManager.class)),
                                 mock(ExpandableNotificationRowDragController.class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index a0e91fc..1305d79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -42,6 +42,7 @@
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -71,6 +72,7 @@
     private Handler mHandler;
     private ExpandableNotificationRow mNotificationRow;
     private Runnable mFalsingCheck;
+    private FeatureFlags mFeatureFlags;
 
     @Rule public MockitoRule mockito = MockitoJUnit.rule();
 
@@ -78,9 +80,10 @@
     public void setUp() throws Exception {
         mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
         mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
+        mFeatureFlags = mock(FeatureFlags.class);
         mSwipeHelper = spy(new NotificationSwipeHelper(
                 mContext.getResources(), ViewConfiguration.get(mContext),
-                new FalsingManagerFake(), SwipeHelper.X, mCallback, mListener));
+                new FalsingManagerFake(), mFeatureFlags, SwipeHelper.X, mCallback, mListener));
         mView = mock(View.class);
         mEvent = mock(MotionEvent.class);
         mMenuRow = mock(NotificationMenuRowPlugin.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 01e9822e..7de3545 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -47,6 +47,9 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserInfoTracker;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController;
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherFeatureController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -99,6 +102,12 @@
     private ArgumentCaptor<ConfigurationListener> mConfigurationListenerCaptor;
     @Captor
     private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardCallbackCaptor;
+    @Mock
+    private StatusBarUserSwitcherFeatureController mStatusBarUserSwitcherFeatureController;
+    @Mock
+    private StatusBarUserSwitcherController mStatusBarUserSwitcherController;
+    @Mock
+    private StatusBarUserInfoTracker mStatusBarUserInfoTracker;
 
     private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
     private KeyguardStatusBarView mKeyguardStatusBarView;
@@ -117,7 +126,11 @@
                             .inflate(R.layout.keyguard_status_bar, null));
         });
 
-        mController = new KeyguardStatusBarViewController(
+        mController = createController();
+    }
+
+    private KeyguardStatusBarViewController createController() {
+        return new KeyguardStatusBarViewController(
                 mKeyguardStatusBarView,
                 mCarrierTextController,
                 mConfigurationController,
@@ -134,7 +147,10 @@
                 mBiometricUnlockController,
                 mStatusBarStateController,
                 mStatusBarContentInsetsProvider,
-                mUserManager
+                mUserManager,
+                mStatusBarUserSwitcherFeatureController,
+                mStatusBarUserSwitcherController,
+                mStatusBarUserInfoTracker
         );
     }
 
@@ -356,6 +372,32 @@
         assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
     }
 
+    @Test
+    public void testNewUserSwitcherDisablesAvatar_newUiOn() {
+        // GIVEN the status bar user switcher chip is enabled
+        when(mStatusBarUserSwitcherFeatureController.isStatusBarUserSwitcherFeatureEnabled())
+                .thenReturn(true);
+
+        // WHEN the controller is created
+        mController = createController();
+
+        // THEN keyguard status bar view avatar is disabled
+        assertThat(mKeyguardStatusBarView.isKeyguardUserAvatarEnabled()).isFalse();
+    }
+
+    @Test
+    public void testNewUserSwitcherDisablesAvatar_newUiOff() {
+        // GIVEN the status bar user switcher chip is disabled
+        when(mStatusBarUserSwitcherFeatureController.isStatusBarUserSwitcherFeatureEnabled())
+                .thenReturn(false);
+
+        // WHEN the controller is created
+        mController = createController();
+
+        // THEN keyguard status bar view avatar is enabled
+        assertThat(mKeyguardStatusBarView.isKeyguardUserAvatarEnabled()).isTrue();
+    }
+
     private void updateStateToNotKeyguard() {
         updateStatusBarState(SHADE);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index dee88db..7347565 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -37,7 +37,6 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -99,7 +98,6 @@
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.idle.IdleHostViewController;
@@ -394,7 +392,7 @@
         mConfiguration.orientation = ORIENTATION_PORTRAIT;
         when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
         mDisplayMetrics.density = 100;
-        when(mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHADE_DRAG)).thenReturn(true);
+        when(mResources.getBoolean(R.bool.config_enableNotificationShadeDrag)).thenReturn(true);
         when(mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade))
                 .thenReturn(NOTIFICATION_SCRIM_TOP_PADDING_IN_SPLIT_SHADE);
         when(mResources.getDimensionPixelSize(R.dimen.qs_panel_width)).thenReturn(400);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index c65a6b6..5891161 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -26,6 +26,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.config.UnfoldTransitionConfig
@@ -60,6 +61,8 @@
     private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider
     @Mock
     private lateinit var configurationController: ConfigurationController
+    @Mock
+    private lateinit var userSwitcherController: StatusBarUserSwitcherController
 
     private lateinit var view: PhoneStatusBarView
     private lateinit var controller: PhoneStatusBarViewController
@@ -187,6 +190,7 @@
         return PhoneStatusBarViewController.Factory(
             Optional.of(sysuiUnfoldComponent),
             Optional.of(progressProvider),
+            userSwitcherController,
             configurationController
         ).create(view, touchEventHandler).also {
             it.init()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index d325840..424a40058 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -128,6 +128,28 @@
     }
 
     @Test
+    public void testCompareTo_withNullEntries() {
+        NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
+        mHeadsUpManager.showNotification(alertEntry);
+
+        assertThat(mHeadsUpManager.compare(alertEntry, null)).isLessThan(0);
+        assertThat(mHeadsUpManager.compare(null, alertEntry)).isGreaterThan(0);
+        assertThat(mHeadsUpManager.compare(null, null)).isEqualTo(0);
+    }
+
+    @Test
+    public void testCompareTo_withNonAlertEntries() {
+        NotificationEntry nonAlertEntry1 = new NotificationEntryBuilder().setTag("nae1").build();
+        NotificationEntry nonAlertEntry2 = new NotificationEntryBuilder().setTag("nae2").build();
+        NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
+        mHeadsUpManager.showNotification(alertEntry);
+
+        assertThat(mHeadsUpManager.compare(alertEntry, nonAlertEntry1)).isLessThan(0);
+        assertThat(mHeadsUpManager.compare(nonAlertEntry1, alertEntry)).isGreaterThan(0);
+        assertThat(mHeadsUpManager.compare(nonAlertEntry1, nonAlertEntry2)).isEqualTo(0);
+    }
+
+    @Test
     public void testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() {
         HeadsUpManager.HeadsUpEntry ongoingCall = mHeadsUpManager.new HeadsUpEntry();
         ongoingCall.setEntry(new NotificationEntryBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
new file mode 100644
index 0000000..ac357ea
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
@@ -0,0 +1,73 @@
+package com.android.systemui.util.drawable
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ShapeDrawable
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class DrawableSizeTest : SysuiTestCase() {
+
+    lateinit var resources: Resources
+
+    @Before
+    fun setUp() {
+        resources = context.resources
+    }
+
+    @Test
+    fun testDownscaleToSize_drawableZeroSize_unchanged() {
+        val drawable = ShapeDrawable()
+        val result = DrawableSize.downscaleToSize(resources, drawable, 100, 100)
+        assertThat(result).isSameInstanceAs(drawable)
+    }
+
+    @Test
+    fun testDownscaleToSize_drawableSmallerThanRequirement_unchanged() {
+        val drawable = BitmapDrawable(resources,
+                Bitmap.createBitmap(
+                        resources.displayMetrics,
+                        150,
+                        150,
+                        Bitmap.Config.ARGB_8888
+                )
+        )
+        val result = DrawableSize.downscaleToSize(resources, drawable, 300, 300)
+        assertThat(result).isSameInstanceAs(drawable)
+    }
+
+    @Test
+    fun testDownscaleToSize_drawableLargerThanRequirementWithDensity_resized() {
+        // This bitmap would actually fail to resize if the method doesn't check for
+        // bitmap dimensions inside drawable.
+        val drawable = BitmapDrawable(resources,
+                Bitmap.createBitmap(
+                        resources.displayMetrics,
+                        150,
+                        75,
+                        Bitmap.Config.ARGB_8888
+                )
+        )
+
+        val result = DrawableSize.downscaleToSize(resources, drawable, 75, 75)
+        assertThat(result).isNotSameInstanceAs(drawable)
+        assertThat(result.intrinsicWidth).isEqualTo(75)
+        assertThat(result.intrinsicHeight).isEqualTo(37)
+    }
+
+    @Test
+    fun testDownscaleToSize_drawableAnimated_unchanged() {
+        val drawable = resources.getDrawable(android.R.drawable.stat_sys_download,
+                resources.newTheme())
+        val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
+        assertThat(result).isSameInstanceAs(drawable)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 9c49e98..ca37a40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -1339,6 +1339,22 @@
         assertThat(mBubbleData.hasOverflowBubbleWithKey(entry.getKey())).isFalse();
     }
 
+    @Test
+    public void testStackViewOnBackPressed_updatesBubbleDataExpandState() {
+        mBubbleController.updateBubble(mBubbleEntry);
+
+        // Expand the stack
+        mBubbleData.setExpanded(true);
+        assertStackExpanded();
+
+        // Hit back
+        BubbleStackView stackView = mBubbleController.getStackView();
+        stackView.onBackPressed();
+
+        // Make sure we're collapsed
+        assertStackCollapsed();
+    }
+
     /** Creates a bubble using the userId and package. */
     private Bubble createBubble(int userId, String pkg) {
         final UserHandle userHandle = new UserHandle(userId);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index e12a82a..d82671d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -1158,6 +1158,22 @@
         assertThat(mBubbleData.hasOverflowBubbleWithKey(entry.getKey())).isFalse();
     }
 
+    @Test
+    public void testStackViewOnBackPressed_updatesBubbleDataExpandState() {
+        mBubbleController.updateBubble(mBubbleEntry);
+
+        // Expand the stack
+        mBubbleData.setExpanded(true);
+        assertStackExpanded();
+
+        // Hit back
+        BubbleStackView stackView = mBubbleController.getStackView();
+        stackView.onBackPressed();
+
+        // Make sure we're collapsed
+        assertStackCollapsed();
+    }
+
     /**
      * Sets the bubble metadata flags for this entry. These flags are normally set by
      * NotificationManagerService when the notification is sent, however, these tests do not
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 6938e25..c9903ea 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -43,6 +43,7 @@
 import android.hardware.camera2.extension.IInitializeSessionCallback;
 import android.hardware.camera2.extension.IPreviewExtenderImpl;
 import android.hardware.camera2.extension.IPreviewImageProcessorImpl;
+import android.hardware.camera2.extension.IProcessResultImpl;
 import android.hardware.camera2.extension.IRequestCallback;
 import android.hardware.camera2.extension.IRequestProcessorImpl;
 import android.hardware.camera2.extension.IRequestUpdateProcessorImpl;
@@ -90,6 +91,7 @@
 import androidx.camera.extensions.impl.PreviewExtenderImpl;
 import androidx.camera.extensions.impl.PreviewExtenderImpl.ProcessorType;
 import androidx.camera.extensions.impl.PreviewImageProcessorImpl;
+import androidx.camera.extensions.impl.ProcessResultImpl;
 import androidx.camera.extensions.impl.RequestUpdateProcessorImpl;
 import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl;
 import androidx.camera.extensions.impl.advanced.AutoAdvancedExtenderImpl;
@@ -124,14 +126,17 @@
     private static final String LATEST_VERSION = "1.2.0";
     private static final String NON_INIT_VERSION_PREFIX = "1.0";
     private static final String ADVANCED_VERSION_PREFIX = "1.2";
-    private static final String[] SUPPORTED_VERSION_PREFIXES = {ADVANCED_VERSION_PREFIX,
-            "1.1", NON_INIT_VERSION_PREFIX};
+    private static final String RESULTS_VERSION_PREFIX = "1.3";
+    private static final String[] SUPPORTED_VERSION_PREFIXES = {RESULTS_VERSION_PREFIX,
+            ADVANCED_VERSION_PREFIX, "1.1", NON_INIT_VERSION_PREFIX};
     private static final boolean EXTENSIONS_PRESENT = checkForExtensions();
     private static final String EXTENSIONS_VERSION = EXTENSIONS_PRESENT ?
             (new ExtensionVersionImpl()).checkApiVersion(LATEST_VERSION) : null;
     private static final boolean ADVANCED_API_SUPPORTED = checkForAdvancedAPI();
     private static final boolean INIT_API_SUPPORTED = EXTENSIONS_PRESENT &&
             (!EXTENSIONS_VERSION.startsWith(NON_INIT_VERSION_PREFIX));
+    private static final boolean RESULT_API_SUPPORTED = EXTENSIONS_PRESENT &&
+            (EXTENSIONS_VERSION.startsWith(RESULTS_VERSION_PREFIX));
 
     private HashMap<String, CameraCharacteristics> mCharacteristicsHashMap = new HashMap<>();
     private HashMap<String, Long> mMetadataVendorIdMap = new HashMap<>();
@@ -1242,7 +1247,7 @@
             }
 
             if (processor != null) {
-                return new PreviewImageProcessorImplStub(processor);
+                return new PreviewImageProcessorImplStub(processor, mCameraId);
             }
 
             return null;
@@ -1332,7 +1337,7 @@
         public ICaptureProcessorImpl getCaptureProcessor() {
             CaptureProcessorImpl captureProcessor = mImageExtender.getCaptureProcessor();
             if (captureProcessor != null) {
-                return new CaptureProcessorImplStub(captureProcessor);
+                return new CaptureProcessorImplStub(captureProcessor, mCameraId);
             }
 
             return null;
@@ -1390,13 +1395,97 @@
 
             return null;
         }
+
+        @Override
+        public CameraMetadataNative getAvailableCaptureRequestKeys() {
+            if (RESULT_API_SUPPORTED) {
+                List<CaptureRequest.Key> supportedCaptureKeys =
+                        mImageExtender.getAvailableCaptureRequestKeys();
+
+                if ((supportedCaptureKeys != null) && !supportedCaptureKeys.isEmpty()) {
+                    CameraMetadataNative ret = new CameraMetadataNative();
+                    long vendorId = mMetadataVendorIdMap.containsKey(mCameraId) ?
+                            mMetadataVendorIdMap.get(mCameraId) : Long.MAX_VALUE;
+                    ret.setVendorId(vendorId);
+                    int requestKeyTags [] = new int[supportedCaptureKeys.size()];
+                    int i = 0;
+                    for (CaptureRequest.Key key : supportedCaptureKeys) {
+                        requestKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
+                    }
+                    ret.set(CameraCharacteristics.REQUEST_AVAILABLE_REQUEST_KEYS, requestKeyTags);
+
+                    return ret;
+                }
+            }
+
+            return null;
+        }
+
+        @Override
+        public CameraMetadataNative getAvailableCaptureResultKeys() {
+            if (RESULT_API_SUPPORTED) {
+                List<CaptureResult.Key> supportedResultKeys =
+                        mImageExtender.getAvailableCaptureResultKeys();
+
+                if ((supportedResultKeys != null) && !supportedResultKeys.isEmpty()) {
+                    CameraMetadataNative ret = new CameraMetadataNative();
+                    long vendorId = mMetadataVendorIdMap.containsKey(mCameraId) ?
+                            mMetadataVendorIdMap.get(mCameraId) : Long.MAX_VALUE;
+                    ret.setVendorId(vendorId);
+                    int resultKeyTags [] = new int[supportedResultKeys.size()];
+                    int i = 0;
+                    for (CaptureResult.Key key : supportedResultKeys) {
+                        resultKeyTags[i++] = CameraMetadataNative.getTag(key.getName(), vendorId);
+                    }
+                    ret.set(CameraCharacteristics.REQUEST_AVAILABLE_RESULT_KEYS, resultKeyTags);
+
+                    return ret;
+                }
+            }
+
+            return null;
+        }
+    }
+
+    private class ProcessResultCallback implements ProcessResultImpl {
+        private final IProcessResultImpl mProcessResult;
+        private final String mCameraId;
+
+        private ProcessResultCallback(IProcessResultImpl processResult, String cameraId) {
+            mProcessResult = processResult;
+            mCameraId = cameraId;
+        }
+
+        @Override
+        public void onCaptureCompleted(long shutterTimestamp,
+                List<Pair<CaptureResult.Key, Object>> result) {
+            if (result == null) {
+                Log.e(TAG, "Invalid capture result received!");
+            }
+
+            CameraMetadataNative captureResults = new CameraMetadataNative();
+            if (mMetadataVendorIdMap.containsKey(mCameraId)) {
+                captureResults.setVendorId(mMetadataVendorIdMap.get(mCameraId));
+            }
+            for (Pair<CaptureResult.Key, Object> pair : result) {
+                captureResults.set(pair.first, pair.second);
+            }
+
+            try {
+                mProcessResult.onCaptureCompleted(shutterTimestamp, captureResults);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Remote client doesn't respond to capture results!");
+            }
+        }
     }
 
     private class CaptureProcessorImplStub extends ICaptureProcessorImpl.Stub {
         private final CaptureProcessorImpl mCaptureProcessor;
+        private final String mCameraId;
 
-        public CaptureProcessorImplStub(CaptureProcessorImpl captureProcessor) {
+        public CaptureProcessorImplStub(CaptureProcessorImpl captureProcessor, String cameraId) {
             mCaptureProcessor = captureProcessor;
+            mCameraId = cameraId;
         }
 
         @Override
@@ -1415,7 +1504,7 @@
         }
 
         @Override
-        public void process(List<CaptureBundle> captureList) {
+        public void process(List<CaptureBundle> captureList, IProcessResultImpl resultCallback) {
             HashMap<Integer, Pair<Image, TotalCaptureResult>> captureMap = new HashMap<>();
             for (CaptureBundle captureBundle : captureList) {
                 captureMap.put(captureBundle.stage, new Pair<> (
@@ -1424,7 +1513,14 @@
                                 captureBundle.sequenceId)));
             }
             if (!captureMap.isEmpty()) {
-                mCaptureProcessor.process(captureMap);
+                if ((resultCallback != null) && (RESULT_API_SUPPORTED)) {
+                    mCaptureProcessor.process(captureMap, new ProcessResultCallback(resultCallback,
+                                    mCameraId), null /*executor*/);
+                } else if (resultCallback == null) {
+                    mCaptureProcessor.process(captureMap);
+                } else {
+                    Log.e(TAG, "Process requests with capture results are not supported!");
+                }
             } else {
                 Log.e(TAG, "Process request with absent capture stages!");
             }
@@ -1433,9 +1529,11 @@
 
     private class PreviewImageProcessorImplStub extends IPreviewImageProcessorImpl.Stub {
         private final PreviewImageProcessorImpl mProcessor;
+        private final String mCameraId;
 
-        public PreviewImageProcessorImplStub(PreviewImageProcessorImpl processor) {
+        public PreviewImageProcessorImplStub(PreviewImageProcessorImpl processor, String cameraId) {
             mProcessor = processor;
+            mCameraId = cameraId;
         }
 
         @Override
@@ -1455,9 +1553,17 @@
 
         @Override
         public void process(android.hardware.camera2.extension.ParcelImage image,
-                CameraMetadataNative result, int sequenceId) {
-            mProcessor.process(new ExtensionImage(image),
-                    new TotalCaptureResult(result, sequenceId));
+                CameraMetadataNative result, int sequenceId, IProcessResultImpl resultCallback) {
+            if ((resultCallback != null) && RESULT_API_SUPPORTED) {
+                mProcessor.process(new ExtensionImage(image),
+                        new TotalCaptureResult(result, sequenceId),
+                        new ProcessResultCallback(resultCallback, mCameraId), null /*executor*/);
+            } else if (resultCallback == null) {
+                mProcessor.process(new ExtensionImage(image),
+                        new TotalCaptureResult(result, sequenceId));
+            } else {
+
+            }
         }
     }
 
diff --git a/proto/src/camera.proto b/proto/src/camera.proto
index 0338b93..2d62f32 100644
--- a/proto/src/camera.proto
+++ b/proto/src/camera.proto
@@ -65,4 +65,6 @@
 
     // The dynamic range profile of the stream
     optional int32 dynamic_range_profile = 14;
+    // The stream use case
+    optional int32 stream_use_case = 15;
 }
diff --git a/services/Android.bp b/services/Android.bp
index b0a5c66..0189303 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -16,6 +16,13 @@
             // "-Xep:AndroidFrameworkBinderIdentity:ERROR",
             "-Xep:AndroidFrameworkCompatChange:ERROR",
             // "-Xep:AndroidFrameworkUid:ERROR",
+            "-Xep:SelfEquals:ERROR",
+            "-Xep:NullTernary:ERROR",
+            "-Xep:TryFailThrowable:ERROR",
+            "-Xep:HashtableContains:ERROR",
+            "-Xep:FormatString:ERROR",
+            "-Xep:ArrayHashCode:ERROR",
+            "-Xep:SelfAssignment:ERROR",
             // NOTE: only enable to generate local patchfiles
             // "-XepPatchChecks:refaster:frameworks/base/errorprone/refaster/EfficientXml.java.refaster",
             // "-XepPatchLocation:/tmp/refaster/",
@@ -183,10 +190,6 @@
     name: "libandroid_servers",
     defaults: ["libservices.core-libs"],
     whole_static_libs: ["libservices.core"],
-    required: [
-        // TODO: remove after NetworkStatsService is moved to the mainline module.
-        "libcom_android_net_module_util_jni",
-    ],
 }
 
 platform_compat_config {
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index e93ac47..8b62a64 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -66,6 +66,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -269,6 +270,7 @@
         void onDoubleTap(int displayId);
 
         void onDoubleTapAndHold(int displayId);
+
     }
 
     public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -2164,4 +2166,23 @@
     public void onDoubleTapAndHold(int displayId) {
         mSystemSupport.onDoubleTapAndHold(displayId);
     }
-}
+
+    /**
+     * Sets the scaling factor for animations.
+     */
+    public void setAnimationScale(float scale) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Settings.Global.putFloat(
+                    mContext.getContentResolver(), Settings.Global.WINDOW_ANIMATION_SCALE, scale);
+            Settings.Global.putFloat(
+                    mContext.getContentResolver(),
+                    Settings.Global.TRANSITION_ANIMATION_SCALE,
+                    scale);
+            Settings.Global.putFloat(
+                    mContext.getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE, scale);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 051281c..fc95cdd 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -1614,8 +1614,8 @@
                 @NonNull IBinder appCallback, @NonNull IResultReceiver receiver)
                 throws RemoteException {
             final int userId = UserHandle.getCallingUserId();
-            activityToken = Objects.requireNonNull(activityToken, "activityToken");
-            appCallback = Objects.requireNonNull(appCallback, "appCallback");
+            Objects.requireNonNull(activityToken, "activityToken");
+            Objects.requireNonNull(appCallback, "appCallback");
 
             boolean restored = false;
             synchronized (mLock) {
diff --git a/services/companion/TEST_MAPPING b/services/companion/TEST_MAPPING
index 63f54fa..4a37cb8 100644
--- a/services/companion/TEST_MAPPING
+++ b/services/companion/TEST_MAPPING
@@ -1,6 +1,12 @@
 {
   "presubmit": [
     {
+      "name": "CtsCompanionDeviceManagerCoreTestCases"
+    },
+    {
+      "name": "CtsCompanionDeviceManagerUiAutomationTestCases"
+    },
+    {
       "name": "CtsOsTestCases",
       "options": [
         {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index c3ab2a7..cef0e83 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -35,10 +35,10 @@
 import static com.android.server.companion.AssociationStore.CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED;
 import static com.android.server.companion.PermissionsUtils.checkCallerCanManageAssociationsForPackage;
 import static com.android.server.companion.PermissionsUtils.checkCallerCanManageCompanionDevice;
-import static com.android.server.companion.PermissionsUtils.enforceCallerCanInteractWithUserId;
 import static com.android.server.companion.PermissionsUtils.enforceCallerCanManageAssociationsForPackage;
 import static com.android.server.companion.PermissionsUtils.enforceCallerCanManageCompanionDevice;
 import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr;
+import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId;
 import static com.android.server.companion.RolesUtils.addRoleHolderForAssociation;
 import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation;
 
@@ -459,7 +459,7 @@
 
         @Override
         public List<AssociationInfo> getAllAssociationsForUser(int userId) throws RemoteException {
-            enforceCallerCanInteractWithUserId(getContext(), userId);
+            enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId);
             enforceCallerCanManageCompanionDevice(getContext(), "getAllAssociationsForUser");
 
             return mAssociationStore.getAssociationsForUser(userId);
@@ -468,7 +468,7 @@
         @Override
         public void addOnAssociationsChangedListener(IOnAssociationsChangedListener listener,
                 int userId) {
-            enforceCallerCanInteractWithUserId(getContext(), userId);
+            enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId);
             enforceCallerCanManageCompanionDevice(getContext(),
                     "addOnAssociationsChangedListener");
 
@@ -478,7 +478,7 @@
         @Override
         public void removeOnAssociationsChangedListener(IOnAssociationsChangedListener listener,
                 int userId) {
-            enforceCallerCanInteractWithUserId(getContext(), userId);
+            enforceCallerIsSystemOrCanInteractWithUserId(getContext(), userId);
             enforceCallerCanManageCompanionDevice(
                     getContext(), "removeOnAssociationsChangedListener");
 
diff --git a/services/companion/java/com/android/server/companion/PermissionsUtils.java b/services/companion/java/com/android/server/companion/PermissionsUtils.java
index 7ebe33e..0e593e1 100644
--- a/services/companion/java/com/android/server/companion/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/PermissionsUtils.java
@@ -114,6 +114,12 @@
         context.enforceCallingPermission(INTERACT_ACROSS_USERS, null);
     }
 
+    static void enforceCallerIsSystemOrCanInteractWithUserId(@NonNull Context context, int userId) {
+        if (getCallingUid() == SYSTEM_UID) return;
+
+        enforceCallerCanInteractWithUserId(context, userId);
+    }
+
     static boolean checkCallerIsSystemOr(@UserIdInt int userId, @NonNull String packageName) {
         final int callingUid = getCallingUid();
         if (callingUid == SYSTEM_UID) return true;
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index bb49ba0..75acf81 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -39,7 +39,6 @@
 
 import java.util.List;
 import java.util.Set;
-import java.util.function.Consumer;
 
 
 /**
@@ -62,7 +61,6 @@
     private final ArraySet<ComponentName> mAllowedActivities;
     @Nullable
     private final ArraySet<ComponentName> mBlockedActivities;
-    private Consumer<ActivityInfo> mActivityBlockedCallback;
 
     @NonNull
     final ArraySet<Integer> mRunningUids = new ArraySet<>();
@@ -83,12 +81,10 @@
             @NonNull ArraySet<UserHandle> allowedUsers,
             @Nullable Set<ComponentName> allowedActivities,
             @Nullable Set<ComponentName> blockedActivities,
-            @NonNull ActivityListener activityListener,
-            @NonNull Consumer<ActivityInfo> activityBlockedCallback) {
+            @NonNull ActivityListener activityListener) {
         mAllowedUsers = allowedUsers;
         mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities);
         mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities);
-        mActivityBlockedCallback = activityBlockedCallback;
         setInterestedWindowFlags(windowFlags, systemWindowFlags);
         mActivityListener = activityListener;
     }
@@ -100,7 +96,6 @@
         for (int i = 0; i < activityCount; i++) {
             final ActivityInfo aInfo = activities.get(i);
             if (!canContainActivity(aInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
-                mActivityBlockedCallback.accept(aInfo);
                 return false;
             }
         }
@@ -110,11 +105,7 @@
     @Override
     public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
             int systemWindowFlags) {
-        if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
-            mActivityBlockedCallback.accept(activityInfo);
-            return false;
-        }
-        return true;
+        return canContainActivity(activityInfo, windowFlags, systemWindowFlags);
     }
 
     @Override
diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java
index e6bfd1f..9d4b50b 100644
--- a/services/companion/java/com/android/server/companion/virtual/InputController.java
+++ b/services/companion/java/com/android/server/companion/virtual/InputController.java
@@ -30,7 +30,6 @@
 import android.hardware.input.VirtualMouseScrollEvent;
 import android.hardware.input.VirtualTouchEvent;
 import android.os.IBinder;
-import android.os.IInputConstants;
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Slog;
@@ -43,6 +42,7 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -76,13 +76,6 @@
     private final DisplayManagerInternal mDisplayManagerInternal;
     private final InputManagerInternal mInputManagerInternal;
 
-    /**
-     * Because the pointer is a singleton, it can only be targeted at one display at a time. Because
-     * multiple mice could be concurrently registered, mice that are associated with a different
-     * display than the current target display should not be allowed to affect the current target.
-     */
-    @VisibleForTesting int mActivePointerDisplayId;
-
     InputController(@NonNull Object lock) {
         this(lock, new NativeWrapper());
     }
@@ -91,18 +84,21 @@
     InputController(@NonNull Object lock, @NonNull NativeWrapper nativeWrapper) {
         mLock = lock;
         mNativeWrapper = nativeWrapper;
-        mActivePointerDisplayId = Display.INVALID_DISPLAY;
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
     }
 
     void close() {
         synchronized (mLock) {
-            for (InputDeviceDescriptor inputDeviceDescriptor : mInputDeviceDescriptors.values()) {
-                mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor());
+            final Iterator<Map.Entry<IBinder, InputDeviceDescriptor>> iterator =
+                    mInputDeviceDescriptors.entrySet().iterator();
+            if (iterator.hasNext()) {
+                final Map.Entry<IBinder, InputDeviceDescriptor> entry = iterator.next();
+                final IBinder token = entry.getKey();
+                final InputDeviceDescriptor inputDeviceDescriptor = entry.getValue();
+                iterator.remove();
+                closeInputDeviceDescriptorLocked(token, inputDeviceDescriptor);
             }
-            mInputDeviceDescriptors.clear();
-            resetMouseValuesLocked();
         }
     }
 
@@ -150,8 +146,6 @@
                     new InputDeviceDescriptor(fd, binderDeathRecipient,
                             InputDeviceDescriptor.TYPE_MOUSE, displayId, phys));
             mInputManagerInternal.setVirtualMousePointerDisplayId(displayId);
-            mInputManagerInternal.setPointerAcceleration(1);
-            mActivePointerDisplayId = displayId;
         }
         try {
             deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0);
@@ -197,23 +191,44 @@
                 throw new IllegalArgumentException(
                         "Could not unregister input device for given token");
             }
-            token.unlinkToDeath(inputDeviceDescriptor.getDeathRecipient(), /* flags= */ 0);
-            mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor());
-            InputManager.getInstance().removeUniqueIdAssociation(inputDeviceDescriptor.getPhys());
-
-            // Reset values to the default if all virtual mice are unregistered, or set display
-            // id if there's another mouse (choose the most recent).
-            if (inputDeviceDescriptor.isMouse()) {
-                updateMouseValuesLocked();
-            }
+            closeInputDeviceDescriptorLocked(token, inputDeviceDescriptor);
         }
     }
 
     @GuardedBy("mLock")
-    private void updateMouseValuesLocked() {
+    private void closeInputDeviceDescriptorLocked(IBinder token,
+            InputDeviceDescriptor inputDeviceDescriptor) {
+        token.unlinkToDeath(inputDeviceDescriptor.getDeathRecipient(), /* flags= */ 0);
+        mNativeWrapper.closeUinput(inputDeviceDescriptor.getFileDescriptor());
+        InputManager.getInstance().removeUniqueIdAssociation(inputDeviceDescriptor.getPhys());
+
+        // Reset values to the default if all virtual mice are unregistered, or set display
+        // id if there's another mouse (choose the most recent). The inputDeviceDescriptor must be
+        // removed from the mInputDeviceDescriptors instance variable prior to this point.
+        if (inputDeviceDescriptor.isMouse()) {
+            if (mInputManagerInternal.getVirtualMousePointerDisplayId()
+                    == inputDeviceDescriptor.getDisplayId()) {
+                updateActivePointerDisplayIdLocked();
+            }
+        }
+    }
+
+    void setShowPointerIcon(boolean visible, int displayId) {
+        mInputManagerInternal.setPointerIconVisible(visible, displayId);
+    }
+
+    void setPointerAcceleration(float pointerAcceleration, int displayId) {
+        mInputManagerInternal.setPointerAcceleration(pointerAcceleration, displayId);
+    }
+
+    void setDisplayEligibilityForPointerCapture(boolean isEligible, int displayId) {
+        mInputManagerInternal.setDisplayEligibilityForPointerCapture(displayId, isEligible);
+    }
+
+    @GuardedBy("mLock")
+    private void updateActivePointerDisplayIdLocked() {
         InputDeviceDescriptor mostRecentlyCreatedMouse = null;
-        for (InputDeviceDescriptor otherInputDeviceDescriptor :
-                mInputDeviceDescriptors.values()) {
+        for (InputDeviceDescriptor otherInputDeviceDescriptor : mInputDeviceDescriptors.values()) {
             if (otherInputDeviceDescriptor.isMouse()) {
                 if (mostRecentlyCreatedMouse == null
                         || (otherInputDeviceDescriptor.getCreationOrderNumber()
@@ -225,20 +240,12 @@
         if (mostRecentlyCreatedMouse != null) {
             mInputManagerInternal.setVirtualMousePointerDisplayId(
                     mostRecentlyCreatedMouse.getDisplayId());
-            mActivePointerDisplayId = mostRecentlyCreatedMouse.getDisplayId();
         } else {
-            // All mice have been unregistered; reset all values.
-            resetMouseValuesLocked();
+            // All mice have been unregistered
+            mInputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY);
         }
     }
 
-    private void resetMouseValuesLocked() {
-        mInputManagerInternal.setVirtualMousePointerDisplayId(Display.INVALID_DISPLAY);
-        mInputManagerInternal.setPointerAcceleration(
-                IInputConstants.DEFAULT_POINTER_ACCELERATION);
-        mActivePointerDisplayId = Display.INVALID_DISPLAY;
-    }
-
     private static String createPhys(@PhysType String type) {
         return String.format("virtual%s:%d", type, sNextPhysId.getAndIncrement());
     }
@@ -269,7 +276,8 @@
                 throw new IllegalArgumentException(
                         "Could not send button event to input device for given token");
             }
-            if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) {
+            if (inputDeviceDescriptor.getDisplayId()
+                    != mInputManagerInternal.getVirtualMousePointerDisplayId()) {
                 throw new IllegalStateException(
                         "Display id associated with this mouse is not currently targetable");
             }
@@ -300,7 +308,8 @@
                 throw new IllegalArgumentException(
                         "Could not send relative event to input device for given token");
             }
-            if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) {
+            if (inputDeviceDescriptor.getDisplayId()
+                    != mInputManagerInternal.getVirtualMousePointerDisplayId()) {
                 throw new IllegalStateException(
                         "Display id associated with this mouse is not currently targetable");
             }
@@ -317,7 +326,8 @@
                 throw new IllegalArgumentException(
                         "Could not send scroll event to input device for given token");
             }
-            if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) {
+            if (inputDeviceDescriptor.getDisplayId()
+                    != mInputManagerInternal.getVirtualMousePointerDisplayId()) {
                 throw new IllegalStateException(
                         "Display id associated with this mouse is not currently targetable");
             }
@@ -334,7 +344,8 @@
                 throw new IllegalArgumentException(
                         "Could not get cursor position for input device for given token");
             }
-            if (inputDeviceDescriptor.getDisplayId() != mActivePointerDisplayId) {
+            if (inputDeviceDescriptor.getDisplayId()
+                    != mInputManagerInternal.getVirtualMousePointerDisplayId()) {
                 throw new IllegalStateException(
                         "Display id associated with this mouse is not currently targetable");
             }
@@ -354,7 +365,6 @@
                 fout.println("          type: " + inputDeviceDescriptor.getType());
                 fout.println("          phys: " + inputDeviceDescriptor.getPhys());
             }
-            fout.println("      Active mouse display id: " + mActivePointerDisplayId);
         }
     }
 
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 98a5ec1..47e218b 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -34,12 +34,9 @@
 import android.companion.virtual.VirtualDeviceParams;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.hardware.display.DisplayManager;
-import android.hardware.input.InputManagerInternal;
 import android.hardware.input.VirtualKeyEvent;
 import android.hardware.input.VirtualMouseButtonEvent;
 import android.hardware.input.VirtualMouseRelativeEvent;
@@ -58,9 +55,8 @@
 import android.util.SparseArray;
 import android.window.DisplayWindowPolicyController;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.BlockedAppActivity;
-import com.android.server.LocalServices;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -86,6 +82,9 @@
     private final VirtualDeviceParams mParams;
     private final Map<Integer, PowerManager.WakeLock> mPerDisplayWakelocks = new ArrayMap<>();
     private final IVirtualDeviceActivityListener mActivityListener;
+    // The default setting for showing the pointer on new displays.
+    @GuardedBy("mVirtualDeviceLock")
+    private boolean mDefaultShowPointerIcon = true;
 
     private ActivityListener createListenerAdapter(int displayId) {
         return new ActivityListener() {
@@ -385,6 +384,25 @@
         }
     }
 
+    @Override // Binder call
+    public void setShowPointerIcon(boolean showPointerIcon) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+                "Permission required to unregister this input device");
+
+        final long binderToken = Binder.clearCallingIdentity();
+        try {
+            synchronized (mVirtualDeviceLock) {
+                mDefaultShowPointerIcon = showPointerIcon;
+                for (int displayId : mVirtualDisplayIds) {
+                    mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(binderToken);
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
         fout.println("  VirtualDevice: ");
@@ -395,6 +413,7 @@
             for (int id : mVirtualDisplayIds) {
                 fout.println("      " + id);
             }
+            fout.println("    mDefaultShowPointerIcon: " + mDefaultShowPointerIcon);
         }
         mInputController.dump(fout);
     }
@@ -406,23 +425,23 @@
                         "Virtual device already have a virtual display with ID " + displayId);
             }
             mVirtualDisplayIds.add(displayId);
+            mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
+            mInputController.setPointerAcceleration(1f, displayId);
+            mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
+                    displayId);
 
             // Since we're being called in the middle of the display being created, we post a
             // task to grab the wakelock instead of doing it synchronously here, to avoid
             // reentrancy  problems.
             mContext.getMainThreadHandler().post(() -> addWakeLockForDisplay(displayId));
 
-            LocalServices.getService(
-                    InputManagerInternal.class).setDisplayEligibilityForPointerCapture(displayId,
-                    false);
             final GenericWindowPolicyController dwpc =
                     new GenericWindowPolicyController(FLAG_SECURE,
                             SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
                             getAllowedUserHandles(),
                             mParams.getAllowedActivities(),
                             mParams.getBlockedActivities(),
-                            createListenerAdapter(displayId),
-                            activityInfo -> onActivityBlocked(displayId, activityInfo));
+                            createListenerAdapter(displayId));
             mWindowPolicyControllers.put(displayId, dwpc);
             return dwpc;
         }
@@ -445,16 +464,6 @@
         }
     }
 
-    private void onActivityBlocked(int displayId, ActivityInfo activityInfo) {
-        Intent intent = BlockedAppActivity.createStreamingBlockedIntent(
-                UserHandle.getUserId(activityInfo.applicationInfo.uid), activityInfo,
-                mAssociationInfo.getDisplayName());
-        mContext.startActivityAsUser(
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
-                ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(),
-                mContext.getUser());
-    }
-
     private ArraySet<UserHandle> getAllowedUserHandles() {
         ArraySet<UserHandle> result = new ArraySet<>();
         DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
@@ -485,9 +494,6 @@
                 mPerDisplayWakelocks.remove(displayId);
             }
             mVirtualDisplayIds.remove(displayId);
-            LocalServices.getService(
-                    InputManagerInternal.class).setDisplayEligibilityForPointerCapture(
-                    displayId, true);
             mWindowPolicyControllers.remove(displayId);
         }
     }
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 7714dbc..91d2f55 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -32,6 +32,7 @@
 import android.util.PackageUtils;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IBinaryTransparencyService;
 import com.android.internal.util.FrameworkStatsLog;
 
@@ -52,11 +53,15 @@
 public class BinaryTransparencyService extends SystemService {
     private static final String TAG = "TransparencyService";
 
-    private static final String VBMETA_DIGEST_UNINITIALIZED = "vbmeta-digest-uninitialized";
-    private static final String VBMETA_DIGEST_UNAVAILABLE = "vbmeta-digest-unavailable";
-    private static final String SYSPROP_NAME_VBETA_DIGEST = "ro.boot.vbmeta.digest";
+    @VisibleForTesting
+    static final String VBMETA_DIGEST_UNINITIALIZED = "vbmeta-digest-uninitialized";
+    @VisibleForTesting
+    static final String VBMETA_DIGEST_UNAVAILABLE = "vbmeta-digest-unavailable";
+    @VisibleForTesting
+    static final String SYSPROP_NAME_VBETA_DIGEST = "ro.boot.vbmeta.digest";
 
-    private static final String BINARY_HASH_ERROR = "SHA256HashError";
+    @VisibleForTesting
+    static final String BINARY_HASH_ERROR = "SHA256HashError";
 
     private final Context mContext;
     private String mVbmetaDigest;
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 48f5b51..a0575cf 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -484,7 +484,9 @@
         HashMap<String, Long> timestamps = readTimestamps();
         try {
             if (proto) {
-                db.addFile(TAG_TOMBSTONE_PROTO, tombstone, 0);
+                if (recordFileTimestamp(tombstone, timestamps)) {
+                    db.addFile(TAG_TOMBSTONE_PROTO, tombstone, 0);
+                }
             } else {
                 final String headers = getBootHeadersToLogAndUpdate();
                 addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE,
@@ -526,16 +528,10 @@
         if (db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
 
         File file = new File(filename);
-        long fileTime = file.lastModified();
-        if (fileTime <= 0) return;  // File does not exist
-
-        if (timestamps.containsKey(filename) && timestamps.get(filename) == fileTime) {
-            return;  // Already logged this particular file
+        if (!recordFileTimestamp(file, timestamps)) {
+            return;
         }
 
-        timestamps.put(filename, fileTime);
-
-
         String fileContents = FileUtils.readTextFile(file, maxSize, TAG_TRUNCATED);
         String text = headers + fileContents + footers;
         // Create an additional report for system server native crashes, with a special tag.
@@ -548,6 +544,19 @@
         addTextToDropBox(db, tag, text, filename, maxSize);
     }
 
+    private static boolean recordFileTimestamp(File file, HashMap<String, Long> timestamps) {
+        final long fileTime = file.lastModified();
+        if (fileTime <= 0) return false;  // File does not exist
+
+        final String filename = file.getPath();
+        if (timestamps.containsKey(filename) && timestamps.get(filename) == fileTime) {
+            return false;  // Already logged this particular file
+        }
+
+        timestamps.put(filename, fileTime);
+        return true;
+    }
+
     private static void addTextToDropBox(DropBoxManager db, String tag, String text,
             String filename, int maxSize) {
         Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
diff --git a/services/core/java/com/android/server/Dumpable.java b/services/core/java/com/android/server/Dumpable.java
deleted file mode 100644
index 004f923..0000000
--- a/services/core/java/com/android/server/Dumpable.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.IndentingPrintWriter;
-
-/**
- * Interface used to dump {@link SystemServer} state that is not associated with any service.
- *
- * <p>See {@link SystemServer.SystemServerDumper} for usage example.
- */
-// TODO(b/149254050): replace / merge with package android.util.Dumpable (it would require
-// exporting IndentingPrintWriter as @SystemApi) and/or changing the method to use a prefix
-public interface Dumpable {
-
-    /**
-     * Dumps the state.
-     */
-    void dump(@NonNull IndentingPrintWriter pw, @Nullable String[] args);
-
-    /**
-     * Gets the name of the dumpable.
-     *
-     * <p>If not overridden, will return the simple class name.
-     */
-    default String getDumpableName() {
-        return Dumpable.this.getClass().getSimpleName();
-    }
-}
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 53b6605..63e7563 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.os.Build;
 import android.os.Process;
-import android.util.IndentingPrintWriter;
+import android.util.Dumpable;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -28,6 +28,7 @@
 import com.android.server.am.ActivityManagerService;
 import com.android.server.utils.TimingsTraceAndSlog;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -196,7 +197,12 @@
     }
 
     @Override
-    public void dump(IndentingPrintWriter pw, String[] args) {
+    public String getDumpableName() {
+        return SystemServerInitThreadPool.class.getSimpleName();
+    }
+
+    @Override
+    public void dump(PrintWriter pw, String[] args) {
         synchronized (LOCK) {
             pw.printf("has instance: %b\n", (sInstance != null));
         }
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index d719d77..12e438d 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -27,8 +27,8 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.util.ArraySet;
+import android.util.Dumpable;
 import android.util.EventLog;
-import android.util.IndentingPrintWriter;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -44,6 +44,7 @@
 import dalvik.system.PathClassLoader;
 
 import java.io.File;
+import java.io.PrintWriter;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
@@ -687,7 +688,12 @@
     }
 
     @Override
-    public void dump(IndentingPrintWriter pw, String[] args) {
+    public String getDumpableName() {
+        return SystemServiceManager.class.getSimpleName();
+    }
+
+    @Override
+    public void dump(PrintWriter pw, String[] args) {
         pw.printf("Current phase: %d\n", mCurrentPhase);
         synchronized (mTargetUsers) {
             if (mCurrentUser != null) {
@@ -711,14 +717,13 @@
             }
         }
         final int startedLen = mServices.size();
+        String prefix = "  ";
         if (startedLen > 0) {
             pw.printf("%d started services:\n", startedLen);
-            pw.increaseIndent();
             for (int i = 0; i < startedLen; i++) {
                 final SystemService service = mServices.get(i);
-                pw.println(service.getClass().getCanonicalName());
+                pw.print(prefix); pw.println(service.getClass().getCanonicalName());
             }
-            pw.decreaseIndent();
         } else {
             pw.println("No started services");
         }
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 3288ca8..b6b3618 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -30,6 +30,10 @@
                 }
             ],
             "file_patterns": ["SensorPrivacyService\\.java"]
+        },
+        {
+            "name": "BinaryTransparencyServiceTest",
+            "file_patterns": ["BinaryTransparencyService\\.java"]
         }
     ],
     "presubmit-large": [
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index ac20a08..8b48d0f 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -16,12 +16,17 @@
 
 package com.android.server;
 
+import static com.android.server.Watchdog.HandlerCheckerAndTimeout.withCustomTimeout;
+import static com.android.server.Watchdog.HandlerCheckerAndTimeout.withDefaultTimeout;
+
 import android.app.IActivityController;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.database.ContentObserver;
 import android.hidl.manager.V1_0.IServiceManager;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Debug;
@@ -35,12 +40,15 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.sysprop.WatchdogProperties;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.ProcessCpuTracker;
 import com.android.internal.os.ZygoteConnectionConstants;
 import com.android.internal.util.FrameworkStatsLog;
@@ -61,10 +69,13 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
-/** This class calls its monitor every minute. Killing this process if they don't return **/
+/**
+ * This class calls its monitor every minute. Killing this process if they don't return
+ **/
 public class Watchdog {
     static final String TAG = "Watchdog";
 
@@ -79,9 +90,7 @@
     //         can trigger the watchdog.
     // Note 2: The debug value is already below the wait time in ZygoteConnection. Wrapped
     //         applications may not work with a debug build. CTS will fail.
-    private static final long DEFAULT_TIMEOUT =
-            (DB ? 10 * 1000 : 60 * 1000) * Build.HW_TIMEOUT_MULTIPLIER;
-    private static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
+    private static final long DEFAULT_TIMEOUT = DB ? 10 * 1000 : 60 * 1000;
 
     // These are temporally ordered: larger values as lateness increases
     private static final int COMPLETED = 0;
@@ -156,34 +165,71 @@
     private final Object mLock = new Object();
 
     /* This handler will be used to post message back onto the main thread */
-    private final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<>();
+    private final ArrayList<HandlerCheckerAndTimeout> mHandlerCheckers = new ArrayList<>();
     private final HandlerChecker mMonitorChecker;
     private ActivityManagerService mActivity;
-
     private IActivityController mController;
     private boolean mAllowRestart = true;
+    // We start with DEFAULT_TIMEOUT. This will then be update with the timeout values from Settings
+    // once the settings provider is initialized.
+    private volatile long mWatchdogTimeoutMillis = DEFAULT_TIMEOUT;
     private final List<Integer> mInterestingJavaPids = new ArrayList<>();
-
     private final TraceErrorLogger mTraceErrorLogger;
 
+    /** Holds a checker and its timeout. */
+    static final class HandlerCheckerAndTimeout {
+        private final HandlerChecker mHandler;
+        private final Optional<Long> mCustomTimeoutMillis;
+
+        private HandlerCheckerAndTimeout(HandlerChecker checker, Optional<Long> timeoutMillis) {
+            this.mHandler = checker;
+            this.mCustomTimeoutMillis = timeoutMillis;
+        }
+
+        HandlerChecker checker() {
+            return mHandler;
+        }
+
+        /** Returns the timeout. */
+        Optional<Long> customTimeoutMillis() {
+            return mCustomTimeoutMillis;
+        }
+
+        /**
+         * Creates a checker with the default timeout. The timeout will use the default value which
+         * is configurable server-side.
+         */
+        static HandlerCheckerAndTimeout withDefaultTimeout(HandlerChecker checker) {
+            return new HandlerCheckerAndTimeout(checker, Optional.empty());
+        }
+
+        /**
+         * Creates a checker with a custom timeout. The timeout overrides the default value and will
+         * always be used.
+         */
+        static HandlerCheckerAndTimeout withCustomTimeout(
+                HandlerChecker checker, long timeoutMillis) {
+            return new HandlerCheckerAndTimeout(checker, Optional.of(timeoutMillis));
+        }
+    }
+
     /**
      * Used for checking status of handle threads and scheduling monitor callbacks.
      */
     public final class HandlerChecker implements Runnable {
         private final Handler mHandler;
         private final String mName;
-        private final long mWaitMax;
         private final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
         private final ArrayList<Monitor> mMonitorQueue = new ArrayList<Monitor>();
+        private long mWaitMax;
         private boolean mCompleted;
         private Monitor mCurrentMonitor;
         private long mStartTime;
         private int mPauseCount;
 
-        HandlerChecker(Handler handler, String name, long waitMaxMillis) {
+        HandlerChecker(Handler handler, String name) {
             mHandler = handler;
             mName = name;
-            mWaitMax = waitMaxMillis;
             mCompleted = true;
         }
 
@@ -193,7 +239,13 @@
             mMonitorQueue.add(monitor);
         }
 
-        public void scheduleCheckLocked() {
+        /**
+         * Schedules a run on the handler thread.
+         *
+         * @param handlerCheckerTimeoutMillis the timeout to use for this run
+         */
+        public void scheduleCheckLocked(long handlerCheckerTimeoutMillis) {
+            mWaitMax = handlerCheckerTimeoutMillis;
             if (mCompleted) {
                 // Safe to update monitors in queue, Handler is not in the middle of work
                 mMonitors.addAll(mMonitorQueue);
@@ -222,10 +274,6 @@
             mHandler.postAtFrontOfQueue(this);
         }
 
-        boolean isOverdueLocked() {
-            return (!mCompleted) && (SystemClock.uptimeMillis() > mStartTime + mWaitMax);
-        }
-
         public int getCompletionStateLocked() {
             if (mCompleted) {
                 return COMPLETED;
@@ -336,36 +384,37 @@
 
     private Watchdog() {
         mThread = new Thread(this::run, "watchdog");
+
         // Initialize handler checkers for each common thread we want to check.  Note
         // that we are not currently checking the background thread, since it can
         // potentially hold longer running operations with no guarantees about the timeliness
         // of operations there.
-
+        //
         // The shared foreground thread is the main checker.  It is where we
         // will also dispatch monitor checks and do other work.
         mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
-                "foreground thread", DEFAULT_TIMEOUT);
-        mHandlerCheckers.add(mMonitorChecker);
+                "foreground thread");
+        mHandlerCheckers.add(withDefaultTimeout(mMonitorChecker));
         // Add checker for main thread.  We only do a quick check since there
         // can be UI running on the thread.
-        mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
-                "main thread", DEFAULT_TIMEOUT));
+        mHandlerCheckers.add(withDefaultTimeout(
+                new HandlerChecker(new Handler(Looper.getMainLooper()), "main thread")));
         // Add checker for shared UI thread.
-        mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
-                "ui thread", DEFAULT_TIMEOUT));
+        mHandlerCheckers.add(withDefaultTimeout(
+                new HandlerChecker(UiThread.getHandler(), "ui thread")));
         // And also check IO thread.
-        mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
-                "i/o thread", DEFAULT_TIMEOUT));
+        mHandlerCheckers.add(withDefaultTimeout(
+                new HandlerChecker(IoThread.getHandler(), "i/o thread")));
         // And the display thread.
-        mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
-                "display thread", DEFAULT_TIMEOUT));
+        mHandlerCheckers.add(withDefaultTimeout(
+                new HandlerChecker(DisplayThread.getHandler(), "display thread")));
         // And the animation thread.
-        mHandlerCheckers.add(new HandlerChecker(AnimationThread.getHandler(),
-                "animation thread", DEFAULT_TIMEOUT));
+        mHandlerCheckers.add(withDefaultTimeout(
+                 new HandlerChecker(AnimationThread.getHandler(), "animation thread")));
         // And the surface animation thread.
-        mHandlerCheckers.add(new HandlerChecker(SurfaceAnimationThread.getHandler(),
-                "surface animation thread", DEFAULT_TIMEOUT));
-
+        mHandlerCheckers.add(withDefaultTimeout(
+                new HandlerChecker(SurfaceAnimationThread.getHandler(),
+                    "surface animation thread")));
         // Initialize monitor for Binder threads.
         addMonitor(new BinderThreadMonitor());
 
@@ -397,6 +446,62 @@
                 android.Manifest.permission.REBOOT, null);
     }
 
+    private static class SettingsObserver extends ContentObserver {
+        private final Uri mUri = Settings.Global.getUriFor(Settings.Global.WATCHDOG_TIMEOUT_MILLIS);
+        private final Context mContext;
+        private final Watchdog mWatchdog;
+
+        SettingsObserver(Context context, Watchdog watchdog) {
+            super(BackgroundThread.getHandler());
+            mContext = context;
+            mWatchdog = watchdog;
+            // Always kick once to ensure that we match current state
+            onChange();
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            if (mUri.equals(uri)) {
+                onChange();
+            }
+        }
+
+        public void onChange() {
+            try {
+                mWatchdog.updateWatchdogTimeout(Settings.Global.getLong(
+                        mContext.getContentResolver(),
+                        Settings.Global.WATCHDOG_TIMEOUT_MILLIS, DEFAULT_TIMEOUT));
+            } catch (RuntimeException e) {
+                Slog.e(TAG, "Exception while reading settings " + e.getMessage(), e);
+            }
+        }
+    }
+
+    /**
+     * Register an observer to listen to settings.
+     *
+     * It needs to be called after the settings service is initialized.
+     */
+    public void registerSettingsObserver(Context context) {
+        context.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.WATCHDOG_TIMEOUT_MILLIS),
+                false,
+                new SettingsObserver(context, this),
+                UserHandle.USER_SYSTEM);
+    }
+
+    /**
+     * Updates watchdog timeout values.
+     */
+    void updateWatchdogTimeout(long timeoutMillis) {
+        // See the notes on DEFAULT_TIMEOUT.
+        if (!DB && timeoutMillis <= ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS) {
+            timeoutMillis = ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS + 1;
+        }
+        mWatchdogTimeoutMillis = timeoutMillis;
+        Slog.i(TAG, "Watchdog timeout updated to " + mWatchdogTimeoutMillis + " millis");
+    }
+
     private static boolean isInterestingJavaProcess(String processName) {
         return processName.equals(StorageManagerService.sMediaStoreAuthorityProcessName)
                 || processName.equals("com.android.phone");
@@ -446,13 +551,17 @@
     }
 
     public void addThread(Handler thread) {
-        addThread(thread, DEFAULT_TIMEOUT);
+        synchronized (mLock) {
+            final String name = thread.getLooper().getThread().getName();
+            mHandlerCheckers.add(withDefaultTimeout(new HandlerChecker(thread, name)));
+        }
     }
 
     public void addThread(Handler thread, long timeoutMillis) {
         synchronized (mLock) {
             final String name = thread.getLooper().getThread().getName();
-            mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
+            mHandlerCheckers.add(
+                    withCustomTimeout(new HandlerChecker(thread, name), timeoutMillis));
         }
     }
 
@@ -471,9 +580,10 @@
      */
     public void pauseWatchingCurrentThread(String reason) {
         synchronized (mLock) {
-            for (HandlerChecker hc : mHandlerCheckers) {
-                if (Thread.currentThread().equals(hc.getThread())) {
-                    hc.pauseLocked(reason);
+            for (HandlerCheckerAndTimeout hc : mHandlerCheckers) {
+                HandlerChecker checker = hc.checker();
+                if (Thread.currentThread().equals(checker.getThread())) {
+                    checker.pauseLocked(reason);
                 }
             }
         }
@@ -493,9 +603,10 @@
      */
     public void resumeWatchingCurrentThread(String reason) {
         synchronized (mLock) {
-            for (HandlerChecker hc : mHandlerCheckers) {
-                if (Thread.currentThread().equals(hc.getThread())) {
-                    hc.resumeLocked(reason);
+            for (HandlerCheckerAndTimeout hc : mHandlerCheckers) {
+                HandlerChecker checker = hc.checker();
+                if (Thread.currentThread().equals(checker.getThread())) {
+                    checker.resumeLocked(reason);
                 }
             }
         }
@@ -516,17 +627,17 @@
     private int evaluateCheckerCompletionLocked() {
         int state = COMPLETED;
         for (int i=0; i<mHandlerCheckers.size(); i++) {
-            HandlerChecker hc = mHandlerCheckers.get(i);
+            HandlerChecker hc = mHandlerCheckers.get(i).checker();
             state = Math.max(state, hc.getCompletionStateLocked());
         }
         return state;
     }
 
-    private ArrayList<HandlerChecker> getBlockedCheckersLocked() {
+    private ArrayList<HandlerChecker> getCheckersWithStateLocked(int completionState) {
         ArrayList<HandlerChecker> checkers = new ArrayList<HandlerChecker>();
         for (int i=0; i<mHandlerCheckers.size(); i++) {
-            HandlerChecker hc = mHandlerCheckers.get(i);
-            if (hc.isOverdueLocked()) {
+            HandlerChecker hc = mHandlerCheckers.get(i).checker();
+            if (hc.getCompletionStateLocked() == completionState) {
                 checkers.add(hc);
             }
         }
@@ -595,20 +706,28 @@
 
     private void run() {
         boolean waitedHalf = false;
+
         while (true) {
             List<HandlerChecker> blockedCheckers = Collections.emptyList();
             String subject = "";
             boolean allowRestart = true;
             int debuggerWasConnected = 0;
             boolean doWaitedHalfDump = false;
+            // The value of mWatchdogTimeoutMillis might change while we are executing the loop.
+            // We store the current value to use a consistent value for all handlers.
+            final long watchdogTimeoutMillis = mWatchdogTimeoutMillis;
+            final long checkIntervalMillis = watchdogTimeoutMillis / 2;
             final ArrayList<Integer> pids;
             synchronized (mLock) {
-                long timeout = CHECK_INTERVAL;
+                long timeout = checkIntervalMillis;
                 // Make sure we (re)spin the checkers that have become idle within
                 // this wait-and-check interval
                 for (int i=0; i<mHandlerCheckers.size(); i++) {
-                    HandlerChecker hc = mHandlerCheckers.get(i);
-                    hc.scheduleCheckLocked();
+                    HandlerCheckerAndTimeout hc = mHandlerCheckers.get(i);
+                    // We pick the watchdog to apply every time we reschedule the checkers. The
+                    // default timeout might have changed since the last run.
+                    hc.checker().scheduleCheckLocked(hc.customTimeoutMillis()
+                            .orElse(watchdogTimeoutMillis * Build.HW_TIMEOUT_MULTIPLIER));
                 }
 
                 if (debuggerWasConnected > 0) {
@@ -633,7 +752,7 @@
                     if (Debug.isDebuggerConnected()) {
                         debuggerWasConnected = 2;
                     }
-                    timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
+                    timeout = checkIntervalMillis - (SystemClock.uptimeMillis() - start);
                 }
 
                 final int waitState = evaluateCheckerCompletionLocked();
@@ -649,6 +768,8 @@
                         Slog.i(TAG, "WAITED_HALF");
                         waitedHalf = true;
                         // We've waited half, but we'd need to do the stack trace dump w/o the lock.
+                        blockedCheckers = getCheckersWithStateLocked(WAITED_HALF);
+                        subject = describeCheckersLocked(blockedCheckers);
                         pids = new ArrayList<>(mInterestingJavaPids);
                         doWaitedHalfDump = true;
                     } else {
@@ -656,90 +777,27 @@
                     }
                 } else {
                     // something is overdue!
-                    blockedCheckers = getBlockedCheckersLocked();
+                    blockedCheckers = getCheckersWithStateLocked(OVERDUE);
                     subject = describeCheckersLocked(blockedCheckers);
                     allowRestart = mAllowRestart;
                     pids = new ArrayList<>(mInterestingJavaPids);
                 }
             } // END synchronized (mLock)
 
-            if (doWaitedHalfDump) {
-                // Get critical event log before logging the half watchdog so that it doesn't
-                // occur in the log.
-                String criticalEvents =
-                        CriticalEventLog.getInstance().logLinesForSystemServerTraceFile();
-                CriticalEventLog.getInstance().logHalfWatchdog(subject);
+            // If we got here, that means that the system is most likely hung.
+            //
+            // First collect stack traces from all threads of the system process.
+            //
+            // Then, if we reached the full timeout, kill this process so that the system will
+            // restart. If we reached half of the timeout, just log some information and continue.
+            logWatchog(doWaitedHalfDump, subject, pids);
 
-                // We've waited half the deadlock-detection interval.  Pull a stack
-                // trace and wait another half.
-                ActivityManagerService.dumpStackTraces(pids, null, null,
-                        getInterestingNativePids(), null, subject, criticalEvents);
+            if (doWaitedHalfDump) {
+                // We have waited for only half of the timeout, we continue to wait for the duration
+                // of the full timeout before killing the process.
                 continue;
             }
 
-            // If we got here, that means that the system is most likely hung.
-            // First collect stack traces from all threads of the system process.
-            // Then kill this process so that the system will restart.
-            EventLog.writeEvent(EventLogTags.WATCHDOG, subject);
-
-            final UUID errorId = mTraceErrorLogger.generateErrorId();
-            if (mTraceErrorLogger.isAddErrorIdEnabled()) {
-                mTraceErrorLogger.addErrorIdToTrace("system_server", errorId);
-                mTraceErrorLogger.addSubjectToTrace(subject, errorId);
-            }
-
-            // Log the atom as early as possible since it is used as a mechanism to trigger
-            // Perfetto. Ideally, the Perfetto trace capture should happen as close to the
-            // point in time when the Watchdog happens as possible.
-            FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject);
-
-            // Get critical event log before logging the watchdog so that it doesn't occur in the
-            // log.
-            String criticalEvents =
-                    CriticalEventLog.getInstance().logLinesForSystemServerTraceFile();
-            CriticalEventLog.getInstance().logWatchdog(subject, errorId);
-
-            long anrTime = SystemClock.uptimeMillis();
-            StringBuilder report = new StringBuilder();
-            report.append(MemoryPressureUtil.currentPsiState());
-            ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(false);
-            StringWriter tracesFileException = new StringWriter();
-            final File stack = ActivityManagerService.dumpStackTraces(
-                    pids, processCpuTracker, new SparseArray<>(), getInterestingNativePids(),
-                    tracesFileException, subject, criticalEvents);
-
-            // Give some extra time to make sure the stack traces get written.
-            // The system's been hanging for a minute, another second or two won't hurt much.
-            SystemClock.sleep(5000);
-
-            processCpuTracker.update();
-            report.append(processCpuTracker.printCurrentState(anrTime));
-            report.append(tracesFileException.getBuffer());
-
-            // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
-            doSysRq('w');
-            doSysRq('l');
-
-            // Try to add the error to the dropbox, but assuming that the ActivityManager
-            // itself may be deadlocked.  (which has happened, causing this statement to
-            // deadlock and the watchdog as a whole to be ineffective)
-            Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
-                    public void run() {
-                        // If a watched thread hangs before init() is called, we don't have a
-                        // valid mActivity. So we can't log the error to dropbox.
-                        if (mActivity != null) {
-                            mActivity.addErrorToDropBox(
-                                    "watchdog", null, "system_server", null, null, null,
-                                    null, report.toString(), stack, null, null, null,
-                                    errorId);
-                        }
-                    }
-                };
-            dropboxThread.start();
-            try {
-                dropboxThread.join(2000);  // wait up to 2 seconds for it to return.
-            } catch (InterruptedException ignored) {}
-
             IActivityController controller;
             synchronized (mLock) {
                 controller = mController;
@@ -785,6 +843,74 @@
         }
     }
 
+    private void logWatchog(boolean halfWatchdog, String subject, ArrayList<Integer> pids) {
+        // Get critical event log before logging the half watchdog so that it doesn't
+        // occur in the log.
+        String criticalEvents =
+                CriticalEventLog.getInstance().logLinesForSystemServerTraceFile();
+        final UUID errorId = mTraceErrorLogger.generateErrorId();
+        if (mTraceErrorLogger.isAddErrorIdEnabled()) {
+            mTraceErrorLogger.addErrorIdToTrace("system_server", errorId);
+            mTraceErrorLogger.addSubjectToTrace(subject, errorId);
+        }
+
+        final String dropboxTag;
+        if (halfWatchdog) {
+            dropboxTag = "pre_watchdog";
+            CriticalEventLog.getInstance().logHalfWatchdog(subject);
+        } else {
+            dropboxTag = "watchdog";
+            CriticalEventLog.getInstance().logWatchdog(subject, errorId);
+            EventLog.writeEvent(EventLogTags.WATCHDOG, subject);
+            // Log the atom as early as possible since it is used as a mechanism to trigger
+            // Perfetto. Ideally, the Perfetto trace capture should happen as close to the
+            // point in time when the Watchdog happens as possible.
+            FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject);
+        }
+
+        long anrTime = SystemClock.uptimeMillis();
+        StringBuilder report = new StringBuilder();
+        report.append(MemoryPressureUtil.currentPsiState());
+        ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(false);
+        StringWriter tracesFileException = new StringWriter();
+        final File stack = ActivityManagerService.dumpStackTraces(
+                pids, processCpuTracker, new SparseArray<>(), getInterestingNativePids(),
+                tracesFileException, subject, criticalEvents);
+        // Give some extra time to make sure the stack traces get written.
+        // The system's been hanging for a whlie, another second or two won't hurt much.
+        SystemClock.sleep(5000);
+        processCpuTracker.update();
+        report.append(processCpuTracker.printCurrentState(anrTime));
+        report.append(tracesFileException.getBuffer());
+
+        if (!halfWatchdog) {
+            // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the
+            // kernel log
+            doSysRq('w');
+            doSysRq('l');
+        }
+
+        // Try to add the error to the dropbox, but assuming that the ActivityManager
+        // itself may be deadlocked.  (which has happened, causing this statement to
+        // deadlock and the watchdog as a whole to be ineffective)
+        Thread dropboxThread = new Thread("watchdogWriteToDropbox") {
+                public void run() {
+                    // If a watched thread hangs before init() is called, we don't have a
+                    // valid mActivity. So we can't log the error to dropbox.
+                    if (mActivity != null) {
+                        mActivity.addErrorToDropBox(
+                                dropboxTag, null, "system_server", null, null, null,
+                                null, report.toString(), stack, null, null, null,
+                                errorId);
+                    }
+                }
+            };
+        dropboxThread.start();
+        try {
+            dropboxThread.join(2000);  // wait up to 2 seconds for it to return.
+        } catch (InterruptedException ignored) { }
+    }
+
     private void doSysRq(char c) {
         try {
             FileWriter sysrq_trigger = new FileWriter("/proc/sysrq-trigger");
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index 2845fbf..6667d1b 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -311,14 +311,15 @@
     }
 
     /**
-     * @return true if the device supports secure ADB over Wi-Fi.
+     * @return true if the device supports secure ADB over Wi-Fi or Ethernet.
      * @hide
      */
     @Override
     public boolean isAdbWifiSupported() {
         mContext.enforceCallingPermission(
                 android.Manifest.permission.MANAGE_DEBUGGING, "AdbService");
-        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
+        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI) ||
+                mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_ETHERNET);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index bcb1be3..940ad73 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -123,6 +123,7 @@
     static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle";
     static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME =
             "kill_bg_restricted_cached_idle_settle_time";
+    static final String KEY_ENABLE_COMPONENT_ALIAS = "enable_experimental_component_alias";
     static final String KEY_COMPONENT_ALIAS_OVERRIDES = "component_alias_overrides";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
@@ -199,6 +200,7 @@
      * Whether or not to enable the extra delays to service restarts on memory pressure.
      */
     private static final boolean DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE = true;
+    private static final boolean DEFAULT_ENABLE_COMPONENT_ALIAS = false;
     private static final String DEFAULT_COMPONENT_ALIAS_OVERRIDES = "";
 
     // Flag stored in the DeviceConfig API.
@@ -595,6 +597,12 @@
             DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE;
 
     /**
+     * Whether to enable "component alias" experimental feature. This can only be enabled
+     * on userdebug or eng builds.
+     */
+    volatile boolean mEnableComponentAlias = DEFAULT_ENABLE_COMPONENT_ALIAS;
+
+    /**
      * Defines component aliases. Format
      * ComponentName ":" ComponentName ( "," ComponentName ":" ComponentName )*
      */
@@ -831,6 +839,7 @@
                             case KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE:
                                 updateEnableExtraServiceRestartDelayOnMemPressure();
                                 break;
+                            case KEY_ENABLE_COMPONENT_ALIAS:
                             case KEY_COMPONENT_ALIAS_OVERRIDES:
                                 updateComponentAliases();
                                 break;
@@ -1269,11 +1278,15 @@
     }
 
     private void updateComponentAliases() {
+        mEnableComponentAlias = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_ENABLE_COMPONENT_ALIAS,
+                DEFAULT_ENABLE_COMPONENT_ALIAS);
         mComponentAliasOverrides = DeviceConfig.getString(
                 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 KEY_COMPONENT_ALIAS_OVERRIDES,
                 DEFAULT_COMPONENT_ALIAS_OVERRIDES);
-        mService.mComponentAliasResolver.update(mComponentAliasOverrides);
+        mService.mComponentAliasResolver.update(mEnableComponentAlias, mComponentAliasOverrides);
     }
 
     private void updateProcessKillTimeout() {
@@ -1512,6 +1525,8 @@
         pw.print("="); pw.println(mPushMessagingOverQuotaBehavior);
         pw.print("  "); pw.print(KEY_FGS_ALLOW_OPT_OUT);
         pw.print("="); pw.println(mFgsAllowOptOut);
+        pw.print("  "); pw.print(KEY_ENABLE_COMPONENT_ALIAS);
+        pw.print("="); pw.println(mEnableComponentAlias);
         pw.print("  "); pw.print(KEY_COMPONENT_ALIAS_OVERRIDES);
         pw.print("="); pw.println(mComponentAliasOverrides);
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 17fc4dd..0310b0f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -459,7 +459,7 @@
      * broadcasts
      */
     private static final boolean ENFORCE_DYNAMIC_RECEIVER_EXPLICIT_EXPORT =
-            SystemProperties.getBoolean("fw.enforce_dynamic_receiver_explicit_export", true);
+            SystemProperties.getBoolean("fw.enforce_dynamic_receiver_explicit_export", false);
 
     static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
     static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
@@ -8066,7 +8066,8 @@
 
             // Load the component aliases.
             t.traceBegin("componentAlias");
-            mComponentAliasResolver.onSystemReady(mConstants.mComponentAliasOverrides);
+            mComponentAliasResolver.onSystemReady(mConstants.mEnableComponentAlias,
+                    mConstants.mComponentAliasOverrides);
             t.traceEnd(); // componentAlias
 
             t.traceEnd(); // PhaseActivityManagerReady
@@ -17905,6 +17906,11 @@
         }
     }
 
+    @Override
+    public boolean isAppFreezerEnabled() {
+        return mOomAdjuster.mCachedAppOptimizer.useFreezer();
+    }
+
     /**
      * Resets the state of the {@link com.android.server.am.AppErrors} instance.
      * This is intended for testing within the CTS only and is protected by
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 6f22c61..7af73eb 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -977,7 +977,7 @@
                 Slog.d(TAG_AM, "pid " + pid + " " + app.processName
                         + " received sync transactions while frozen, killing");
                 app.killLocked("Sync transaction while in frozen state",
-                        ApplicationExitInfo.REASON_OTHER,
+                        ApplicationExitInfo.REASON_FREEZER,
                         ApplicationExitInfo.SUBREASON_FREEZER_BINDER_TRANSACTION, true);
                 processKilled = true;
             }
@@ -990,7 +990,7 @@
             Slog.d(TAG_AM, "Unable to query binder frozen info for pid " + pid + " "
                     + app.processName + ". Killing it. Exception: " + e);
             app.killLocked("Unable to query binder frozen stats",
-                    ApplicationExitInfo.REASON_OTHER,
+                    ApplicationExitInfo.REASON_FREEZER,
                     ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
             processKilled = true;
         }
@@ -1007,7 +1007,7 @@
             Slog.e(TAG_AM, "Unable to unfreeze binder for " + pid + " " + app.processName
                     + ". Killing it");
             app.killLocked("Unable to unfreeze",
-                    ApplicationExitInfo.REASON_OTHER,
+                    ApplicationExitInfo.REASON_FREEZER,
                     ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
             return;
         }
@@ -1423,7 +1423,7 @@
                     mFreezeHandler.post(() -> {
                         synchronized (mAm) {
                             proc.killLocked("Unable to freeze binder interface",
-                                    ApplicationExitInfo.REASON_OTHER,
+                                    ApplicationExitInfo.REASON_FREEZER,
                                     ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
                         }
                     });
@@ -1477,7 +1477,7 @@
                 mFreezeHandler.post(() -> {
                     synchronized (mAm) {
                         proc.killLocked("Unable to freeze binder interface",
-                                ApplicationExitInfo.REASON_OTHER,
+                                ApplicationExitInfo.REASON_FREEZER,
                                 ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
                     }
                 });
diff --git a/services/core/java/com/android/server/am/ComponentAliasResolver.java b/services/core/java/com/android/server/am/ComponentAliasResolver.java
index 23553a7..aef7a6c 100644
--- a/services/core/java/com/android/server/am/ComponentAliasResolver.java
+++ b/services/core/java/com/android/server/am/ComponentAliasResolver.java
@@ -30,6 +30,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.Binder;
+import android.os.Build;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -56,6 +57,8 @@
  * "quick & dirty". For example, to define aliases, we use a regular intent filter and meta-data
  * in the manifest, instead of adding proper tags/attributes to AndroidManifest.xml.
  *
+ * Because it's an experimental feature, it can't be enabled on a user build.
+ *
  * Also, for now, aliases can be defined across any packages, but in the final version, there'll
  * be restrictions:
  * - We probably should only allow either privileged or preinstalled apps.
@@ -78,6 +81,9 @@
     private final Context mContext;
 
     @GuardedBy("mLock")
+    private boolean mEnabledByDeviceConfig;
+
+    @GuardedBy("mLock")
     private boolean mEnabled;
 
     @GuardedBy("mLock")
@@ -141,7 +147,7 @@
     /**
      * Call this on systemRead().
      */
-    public void onSystemReady(String overrides) {
+    public void onSystemReady(boolean enabledByDeviceConfig, String overrides) {
         synchronized (mLock) {
             mPlatformCompat = (PlatformCompat) ServiceManager.getService(
                     Context.PLATFORM_COMPAT_SERVICE);
@@ -149,19 +155,21 @@
                     mCompatChangeListener);
         }
         if (DEBUG) Slog.d(TAG, "Compat listener set.");
-        update(overrides);
+        update(enabledByDeviceConfig, overrides);
     }
 
     /**
      * (Re-)loads aliases from <meta-data> and the device config override.
      */
-    public void update(String overrides) {
+    public void update(boolean enabledByDeviceConfig, String overrides) {
         synchronized (mLock) {
             if (mPlatformCompat == null) {
                 return; // System not ready.
             }
-            final boolean enabled = mPlatformCompat.isChangeEnabledByPackageName(
-                    USE_EXPERIMENTAL_COMPONENT_ALIAS, "android", UserHandle.USER_SYSTEM);
+            final boolean enabled = Build.isDebuggable()
+                    && (enabledByDeviceConfig
+                        || mPlatformCompat.isChangeEnabledByPackageName(
+                        USE_EXPERIMENTAL_COMPONENT_ALIAS, "android", UserHandle.USER_SYSTEM));
             if (enabled != mEnabled) {
                 Slog.i(TAG, (enabled ? "Enabling" : "Disabling") + " component aliases...");
                 if (enabled) {
@@ -172,6 +180,7 @@
                 }
             }
             mEnabled = enabled;
+            mEnabledByDeviceConfig = enabledByDeviceConfig;
             mOverrideString = overrides;
 
             if (mEnabled) {
@@ -184,7 +193,7 @@
 
     private void refresh() {
         synchronized (mLock) {
-            update(mOverrideString);
+            update(mEnabledByDeviceConfig, mOverrideString);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index e4c0846..481b6dd 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2034,6 +2034,11 @@
         }
     }
 
+    /**
+     * Tell WindowManager we're ready to unfreeze the screen, at its leisure. Note that there is
+     * likely a lot going on, and WM won't unfreeze until the drawing is all done, so
+     * the actual unfreeze may still not happen for a long time; this is expected.
+     */
     @VisibleForTesting
     void unfreezeScreen() {
         TimingsTraceAndSlog t = new TimingsTraceAndSlog();
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 960fbf1..4eba771 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -43,6 +43,7 @@
 import android.service.games.IGameSessionController;
 import android.service.games.IGameSessionService;
 import android.util.Slog;
+import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost.SurfacePackage;
 
 import com.android.internal.annotations.GuardedBy;
@@ -237,7 +238,7 @@
                 mTaskSystemBarsVisibilityListener);
 
         for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
-            destroyGameSessionFromRecord(gameSessionRecord);
+            destroyGameSessionFromRecordLocked(gameSessionRecord);
         }
         mGameSessions.clear();
 
@@ -472,7 +473,7 @@
         }
 
         try {
-            mWindowManagerInternal.addTaskOverlay(
+            mWindowManagerInternal.addTrustedTaskOverlay(
                     taskId,
                     createGameSessionResult.getSurfacePackage());
         } catch (IllegalArgumentException ex) {
@@ -510,14 +511,15 @@
             }
             return;
         }
-        destroyGameSessionFromRecord(gameSessionRecord);
+        destroyGameSessionFromRecordLocked(gameSessionRecord);
     }
 
-    private void destroyGameSessionFromRecord(@NonNull GameSessionRecord gameSessionRecord) {
+    @GuardedBy("mLock")
+    private void destroyGameSessionFromRecordLocked(@NonNull GameSessionRecord gameSessionRecord) {
         SurfacePackage surfacePackage = gameSessionRecord.getSurfacePackage();
         if (surfacePackage != null) {
             try {
-                mWindowManagerInternal.removeTaskOverlay(
+                mWindowManagerInternal.removeTrustedTaskOverlay(
                         gameSessionRecord.getTaskId(),
                         surfacePackage);
             } catch (IllegalArgumentException ex) {
@@ -586,17 +588,29 @@
 
     @VisibleForTesting
     void takeScreenshot(int taskId, @NonNull AndroidFuture callback) {
+        GameSessionRecord gameSessionRecord;
         synchronized (mLock) {
-            boolean isTaskAssociatedWithGameSession = mGameSessions.containsKey(taskId);
-            if (!isTaskAssociatedWithGameSession) {
+            gameSessionRecord = mGameSessions.get(taskId);
+            if (gameSessionRecord == null) {
                 Slog.w(TAG, "No game session found for id: " + taskId);
                 callback.complete(GameScreenshotResult.createInternalErrorResult());
                 return;
             }
         }
 
+        final SurfacePackage overlaySurfacePackage = gameSessionRecord.getSurfacePackage();
+        final SurfaceControl overlaySurfaceControl =
+                overlaySurfacePackage != null ? overlaySurfacePackage.getSurfaceControl() : null;
         mBackgroundExecutor.execute(() -> {
-            final Bitmap bitmap = mWindowManagerService.captureTaskBitmap(taskId);
+            final SurfaceControl.LayerCaptureArgs.Builder layerCaptureArgsBuilder =
+                    new SurfaceControl.LayerCaptureArgs.Builder(/* layer */ null);
+            if (overlaySurfaceControl != null) {
+                SurfaceControl[] excludeLayers = new SurfaceControl[1];
+                excludeLayers[0] = overlaySurfaceControl;
+                layerCaptureArgsBuilder.setExcludeLayers(excludeLayers);
+            }
+            final Bitmap bitmap = mWindowManagerService.captureTaskBitmap(taskId,
+                    layerCaptureArgsBuilder);
             if (bitmap == null) {
                 Slog.w(TAG, "Could not get bitmap for id: " + taskId);
                 callback.complete(GameScreenshotResult.createInternalErrorResult());
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 366718c..90aefe0 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -35,6 +35,8 @@
 import android.app.IActivityManager;
 import android.app.StatsManager;
 import android.app.StatsManager.StatsPullAtomCallback;
+import android.app.usage.StorageStats;
+import android.app.usage.StorageStatsManager;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
@@ -78,6 +80,7 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -111,6 +114,7 @@
     private final PackageManagerInternal mPackageManagerInternal;
     private final IActivityManager mIActivityManager;
     private final UserManager mUserManager;
+    private final StorageStatsManager mStorageStatsManager;
 
     @GuardedBy("mLock")
     private final SparseArray<Map<String, UserLevelState>> mUserStates = new SparseArray<>();
@@ -147,6 +151,7 @@
         mPackageManagerInternal = injector.getPackageManagerInternal();
         mIActivityManager = injector.getActivityManager();
         mUserManager = injector.getUserManager();
+        mStorageStatsManager = injector.getStorageStatsManager();
         mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore();
         mBackgroundExecutor = injector.getBackgroundExecutor();
         mOatArtifactDeletionEnabled = injector.isOatArtifactDeletionEnabled();
@@ -217,7 +222,7 @@
      */
     boolean isHibernatingForUser(String packageName, int userId) {
         String methodName = "isHibernatingForUser";
-        if (!checkHibernationEnabled(methodName)) {
+        if (!sIsServiceEnabled) {
             return false;
         }
         getContext().enforceCallingOrSelfPermission(
@@ -230,8 +235,10 @@
             }
             final Map<String, UserLevelState> packageStates = mUserStates.get(userId);
             final UserLevelState pkgState = packageStates.get(packageName);
-            if (pkgState == null) {
-                Slog.e(TAG, String.format("Package %s is not installed for user %s",
+            if (pkgState == null
+                    || !mPackageManagerInternal.canQueryPackage(
+                            Binder.getCallingUid(), packageName)) {
+                Slog.e(TAG, TextUtils.formatSimple("Package %s is not installed for user %s",
                         packageName, userId));
                 return false;
             }
@@ -246,7 +253,7 @@
      * @param packageName package to check
      */
     boolean isHibernatingGlobally(String packageName) {
-        if (!checkHibernationEnabled("isHibernatingGlobally")) {
+        if (!sIsServiceEnabled) {
             return false;
         }
         getContext().enforceCallingOrSelfPermission(
@@ -254,7 +261,9 @@
                 "Caller does not have MANAGE_APP_HIBERNATION permission.");
         synchronized (mLock) {
             GlobalLevelState state = mGlobalHibernationStates.get(packageName);
-            if (state == null) {
+            if (state == null
+                    || !mPackageManagerInternal.canQueryPackage(
+                            Binder.getCallingUid(), packageName)) {
                 // This API can be legitimately called before installation finishes as part of
                 // dex optimization, so we just return false here.
                 return false;
@@ -272,7 +281,7 @@
      */
     void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
         String methodName = "setHibernatingForUser";
-        if (!checkHibernationEnabled(methodName)) {
+        if (!sIsServiceEnabled) {
             return;
         }
         getContext().enforceCallingOrSelfPermission(
@@ -285,8 +294,10 @@
             }
             final Map<String, UserLevelState> packageStates = mUserStates.get(realUserId);
             final UserLevelState pkgState = packageStates.get(packageName);
-            if (pkgState == null) {
-                Slog.e(TAG, String.format("Package %s is not installed for user %s",
+            if (pkgState == null
+                    || !mPackageManagerInternal.canQueryPackage(
+                            Binder.getCallingUid(), packageName)) {
+                Slog.e(TAG, TextUtils.formatSimple("Package %s is not installed for user %s",
                         packageName, realUserId));
                 return;
             }
@@ -297,7 +308,8 @@
 
             pkgState.hibernated = isHibernating;
             if (isHibernating) {
-                mBackgroundExecutor.execute(() -> hibernatePackageForUser(packageName, realUserId));
+                mBackgroundExecutor.execute(
+                        () -> hibernatePackageForUser(packageName, realUserId, pkgState));
             } else {
                 mBackgroundExecutor.execute(
                         () -> unhibernatePackageForUser(packageName, realUserId));
@@ -326,7 +338,7 @@
      * @param isHibernating new hibernation state
      */
     void setHibernatingGlobally(String packageName, boolean isHibernating) {
-        if (!checkHibernationEnabled("setHibernatingGlobally")) {
+        if (!sIsServiceEnabled) {
             return;
         }
         getContext().enforceCallingOrSelfPermission(
@@ -334,8 +346,11 @@
                 "Caller does not have MANAGE_APP_HIBERNATION permission.");
         synchronized (mLock) {
             GlobalLevelState state = mGlobalHibernationStates.get(packageName);
-            if (state == null) {
-                Slog.e(TAG, String.format("Package %s is not installed for any user", packageName));
+            if (state == null
+                    || !mPackageManagerInternal.canQueryPackage(
+                            Binder.getCallingUid(), packageName)) {
+                Slog.e(TAG, TextUtils.formatSimple(
+                        "Package %s is not installed for any user", packageName));
                 return;
             }
             if (state.hibernated != isHibernating) {
@@ -359,7 +374,7 @@
     @NonNull List<String> getHibernatingPackagesForUser(int userId) {
         ArrayList<String> hibernatingPackages = new ArrayList<>();
         String methodName = "getHibernatingPackagesForUser";
-        if (!checkHibernationEnabled(methodName)) {
+        if (!sIsServiceEnabled) {
             return hibernatingPackages;
         }
         getContext().enforceCallingOrSelfPermission(
@@ -372,6 +387,12 @@
             }
             Map<String, UserLevelState> userStates = mUserStates.get(userId);
             for (UserLevelState state : userStates.values()) {
+                String packageName = state.packageName;
+                if (!mPackageManagerInternal.canQueryPackage(
+                        Binder.getCallingUid(), packageName)) {
+                    // Package is not visible to caller
+                    continue;
+                }
                 if (state.hibernated) {
                     hibernatingPackages.add(state.packageName);
                 }
@@ -390,6 +411,9 @@
             @Nullable Set<String> packageNames, int userId) {
         Map<String, HibernationStats> statsMap = new ArrayMap<>();
         String methodName = "getHibernationStatsForUser";
+        if (!sIsServiceEnabled) {
+            return statsMap;
+        }
         getContext().enforceCallingOrSelfPermission(
                 android.Manifest.permission.MANAGE_APP_HIBERNATION,
                 "Caller does not have MANAGE_APP_HIBERNATION permission.");
@@ -412,8 +436,9 @@
                                     + "the package was uninstalled? ", pkgName, userId));
                     continue;
                 }
-                HibernationStats stats = new HibernationStats(
-                        mGlobalHibernationStates.get(pkgName).savedByte);
+                long diskBytesSaved = mGlobalHibernationStates.get(pkgName).savedByte
+                        + userPackageStates.get(pkgName).savedByte;
+                HibernationStats stats = new HibernationStats(diskBytesSaved);
                 statsMap.put(pkgName, stats);
             }
         }
@@ -424,16 +449,28 @@
      * Put an app into hibernation for a given user, allowing user-level optimizations to occur. Do
      * not hold {@link #mLock} while calling this to avoid deadlock scenarios.
      */
-    private void hibernatePackageForUser(@NonNull String packageName, int userId) {
+    private void hibernatePackageForUser(@NonNull String packageName, int userId,
+            UserLevelState state) {
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage");
         final long caller = Binder.clearCallingIdentity();
         try {
+            ApplicationInfo info = mIPackageManager.getApplicationInfo(
+                    packageName, PACKAGE_MATCH_FLAGS, userId);
+            StorageStats stats = mStorageStatsManager.queryStatsForPackage(
+                    info.storageUuid, packageName, new UserHandle(userId));
             mIActivityManager.forceStopPackage(packageName, userId);
             mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId,
                     null /* observer */);
+            synchronized (mLock) {
+                state.savedByte = stats.getCacheBytes();
+            }
         } catch (RemoteException e) {
             throw new IllegalStateException(
                     "Failed to hibernate due to manager not being available", e);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.e(TAG, "Package name not found when querying storage stats", e);
+        } catch (IOException e) {
+            Slog.e(TAG, "Storage device not found", e);
         } finally {
             Binder.restoreCallingIdentity(caller);
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
@@ -677,6 +714,7 @@
         for (String key : properties.getKeyset()) {
             if (TextUtils.equals(KEY_APP_HIBERNATION_ENABLED, key)) {
                 sIsServiceEnabled = isDeviceConfigAppHibernationEnabled();
+                Slog.d(TAG, "App hibernation changed to enabled=" + sIsServiceEnabled);
                 break;
             }
         }
@@ -721,13 +759,6 @@
         return true;
     }
 
-    private boolean checkHibernationEnabled(String methodName) {
-        if (!sIsServiceEnabled) {
-            Slog.w(TAG, String.format("Attempted to call %s on unsupported device.", methodName));
-        }
-        return sIsServiceEnabled;
-    }
-
     private void dump(PrintWriter pw) {
         // Check usage stats permission since hibernation indirectly informs usage.
         if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
@@ -923,6 +954,8 @@
 
         UserManager getUserManager();
 
+        StorageStatsManager getStorageStatsManager();
+
         Executor getBackgroundExecutor();
 
         UsageStatsManagerInternal getUsageStatsManagerInternal();
@@ -972,6 +1005,11 @@
         }
 
         @Override
+        public StorageStatsManager getStorageStatsManager() {
+            return mContext.getSystemService(StorageStatsManager.class);
+        }
+
+        @Override
         public Executor getBackgroundExecutor() {
             return mScheduledExecutorService;
         }
diff --git a/services/core/java/com/android/server/apphibernation/UserLevelState.java b/services/core/java/com/android/server/apphibernation/UserLevelState.java
index 68c363c..6a489d2 100644
--- a/services/core/java/com/android/server/apphibernation/UserLevelState.java
+++ b/services/core/java/com/android/server/apphibernation/UserLevelState.java
@@ -28,6 +28,8 @@
 
     public String packageName;
     public boolean hibernated;
+    // Saved bytes from user level hibernation.
+    public long savedByte;
     @CurrentTimeMillisLong
     public long lastUnhibernatedMs;
 
@@ -36,6 +38,7 @@
     UserLevelState(UserLevelState state) {
         packageName = state.packageName;
         hibernated = state.hibernated;
+        savedByte = state.savedByte;
         lastUnhibernatedMs = state.lastUnhibernatedMs;
     }
 
@@ -44,6 +47,7 @@
         return "UserLevelState{"
                 + "packageName='" + packageName + '\''
                 + ", hibernated=" + hibernated + '\''
+                + ", savedByte=" + savedByte + '\''
                 + ", lastUnhibernated=" + DATE_FORMAT.format(lastUnhibernatedMs)
                 + '}';
     }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 5330845..daf3561 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -500,12 +500,11 @@
         }
     }
 
-    /*package*/ void setWiredDeviceConnectionState(int type,
-            @AudioService.ConnectionState int state, String address, String name,
-            String caller) {
+    /*package*/ void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
+            @AudioService.ConnectionState int state, String caller) {
         //TODO move logging here just like in setBluetooth* methods
         synchronized (mDeviceStateLock) {
-            mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
+            mDeviceInventory.setWiredDeviceConnectionState(attributes, state, caller);
         }
     }
 
@@ -1013,11 +1012,9 @@
         }
     }
 
-    /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
-                                                       String deviceName) {
+    /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect) {
         synchronized (mDeviceStateLock) {
-            return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName,
-                    false /*for test*/);
+            return mDeviceInventory.handleDeviceConnection(attributes, connect, false /*for test*/);
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 4ae1bd37..0e29041 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -230,19 +230,15 @@
      * A class just for packaging up a set of connection parameters.
      */
     /*package*/ class WiredDeviceConnectionState {
-        public final int mType;
+        public final AudioDeviceAttributes mAttributes;
         public final @AudioService.ConnectionState int mState;
-        public final String mAddress;
-        public final String mName;
         public final String mCaller;
         public boolean mForTest = false;
 
-        /*package*/ WiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
-                                               String address, String name, String caller) {
-            mType = type;
+        /*package*/ WiredDeviceConnectionState(AudioDeviceAttributes attributes,
+                @AudioService.ConnectionState int state, String caller) {
+            mAttributes = attributes;
             mState = state;
-            mAddress = address;
-            mName = name;
             mCaller = caller;
         }
     }
@@ -280,11 +276,10 @@
         synchronized (mDevicesLock) {
             //TODO iterate on mApmConnectedDevices instead once it handles all device types
             for (DeviceInfo di : mConnectedDevices.values()) {
-                mAudioSystem.setDeviceConnectionState(
-                        di.mDeviceType,
-                        AudioSystem.DEVICE_STATE_AVAILABLE,
+                mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(di.mDeviceType,
                         di.mDeviceAddress,
-                        di.mDeviceName,
+                        di.mDeviceName),
+                        AudioSystem.DEVICE_STATE_AVAILABLE,
                         di.mDeviceCodecFormat);
             }
         }
@@ -519,41 +514,45 @@
 
     /*package*/ void onSetWiredDeviceConnectionState(
                             AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
+        int type = wdcs.mAttributes.getInternalType();
+
         AudioService.sDeviceLogger.log(new AudioServiceEvents.WiredDevConnectEvent(wdcs));
 
         MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
                 + "onSetWiredDeviceConnectionState")
-                .set(MediaMetrics.Property.ADDRESS, wdcs.mAddress)
-                .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(wdcs.mType))
+                .set(MediaMetrics.Property.ADDRESS, wdcs.mAttributes.getAddress())
+                .set(MediaMetrics.Property.DEVICE,
+                        AudioSystem.getDeviceName(type))
                 .set(MediaMetrics.Property.STATE,
                         wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED
                                 ? MediaMetrics.Value.DISCONNECTED : MediaMetrics.Value.CONNECTED);
         synchronized (mDevicesLock) {
             if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
-                    && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
+                    && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
                 mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/,
                         "onSetWiredDeviceConnectionState state DISCONNECTED");
             }
 
-            if (!handleDeviceConnection(wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED,
-                    wdcs.mType, wdcs.mAddress, wdcs.mName, wdcs.mForTest)) {
+            if (!handleDeviceConnection(wdcs.mAttributes,
+                    wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) {
                 // change of connection state failed, bailout
                 mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")
                         .record();
                 return;
             }
             if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
-                if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
+                if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
                     mDeviceBroker.setBluetoothA2dpOnInt(false, false /*fromA2dp*/,
                             "onSetWiredDeviceConnectionState state not DISCONNECTED");
                 }
-                mDeviceBroker.checkMusicActive(wdcs.mType, wdcs.mCaller);
+                mDeviceBroker.checkMusicActive(type, wdcs.mCaller);
             }
-            if (wdcs.mType == AudioSystem.DEVICE_OUT_HDMI) {
+            if (type == AudioSystem.DEVICE_OUT_HDMI) {
                 mDeviceBroker.checkVolumeCecOnHdmiConnection(wdcs.mState, wdcs.mCaller);
             }
-            sendDeviceConnectionIntent(wdcs.mType, wdcs.mState, wdcs.mAddress, wdcs.mName);
-            updateAudioRoutes(wdcs.mType, wdcs.mState);
+            sendDeviceConnectionIntent(type, wdcs.mState,
+                    wdcs.mAttributes.getAddress(), wdcs.mAttributes.getName());
+            updateAudioRoutes(type, wdcs.mState);
         }
         mmi.record();
     }
@@ -572,12 +571,12 @@
                 return;
             }
             // Toggle HDMI to retrigger broadcast with proper formats.
-            setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
-                    AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
-                    "android"); // disconnect
-            setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
-                    AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
-                    "android"); // reconnect
+            setWiredDeviceConnectionState(
+                    new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
+                    AudioSystem.DEVICE_STATE_UNAVAILABLE, "android"); // disconnect
+            setWiredDeviceConnectionState(
+                    new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
+                    AudioSystem.DEVICE_STATE_AVAILABLE, "android"); // reconnect
         }
         mmi.record();
     }
@@ -707,16 +706,17 @@
 
     /**
      * Implements the communication with AudioSystem to (dis)connect a device in the native layers
+     * @param attributes the attributes of the device
      * @param connect true if connection
-     * @param device the device type
-     * @param address the address of the device
-     * @param deviceName human-readable name of device
      * @param isForTesting if true, not calling AudioSystem for the connection as this is
      *                    just for testing
      * @return false if an error was reported by AudioSystem
      */
-    /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
-            String deviceName, boolean isForTesting) {
+    /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
+            boolean isForTesting) {
+        int device = attributes.getInternalType();
+        String address = attributes.getAddress();
+        String deviceName = attributes.getName();
         if (AudioService.DEBUG_DEVICES) {
             Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:"
                     + Integer.toHexString(device) + " address:" + address
@@ -743,9 +743,8 @@
                 if (isForTesting) {
                     res = AudioSystem.AUDIO_STATUS_OK;
                 } else {
-                    res = mAudioSystem.setDeviceConnectionState(device,
-                            AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName,
-                            AudioSystem.AUDIO_FORMAT_DEFAULT);
+                    res = mAudioSystem.setDeviceConnectionState(attributes,
+                            AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
                 }
                 if (res != AudioSystem.AUDIO_STATUS_OK) {
                     final String reason = "not connecting device 0x" + Integer.toHexString(device)
@@ -762,9 +761,8 @@
                 mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
                 return true;
             } else if (!connect && isConnected) {
-                mAudioSystem.setDeviceConnectionState(device,
-                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName,
-                        AudioSystem.AUDIO_FORMAT_DEFAULT);
+                mAudioSystem.setDeviceConnectionState(attributes,
+                        AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
                 // always remove even if disconnection failed
                 mConnectedDevices.remove(deviceKey);
                 mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
@@ -941,13 +939,13 @@
         return delay;
     }
 
-    /*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
-                                                  String address, String name, String caller) {
+    /*package*/ int setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
+            @AudioService.ConnectionState int state, String caller) {
         synchronized (mDevicesLock) {
-            int delay = checkSendBecomingNoisyIntentInt(type, state, AudioSystem.DEVICE_NONE);
+            int delay = checkSendBecomingNoisyIntentInt(
+                    attributes.getInternalType(), state, AudioSystem.DEVICE_NONE);
             mDeviceBroker.postSetWiredDeviceConnectionState(
-                    new WiredDeviceConnectionState(type, state, address, name, caller),
-                    delay);
+                    new WiredDeviceConnectionState(attributes, state, caller), delay);
             return delay;
         }
     }
@@ -955,8 +953,7 @@
     /*package*/ void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
             @AudioService.ConnectionState int state) {
         final WiredDeviceConnectionState connection = new WiredDeviceConnectionState(
-                device.getInternalType(), state, device.getAddress(),
-                "test device", "com.android.server.audio");
+                device, state, "com.android.server.audio");
         connection.mForTest = true;
         onSetWiredDeviceConnectionState(connection);
     }
@@ -972,8 +969,9 @@
         mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource);
         // at this point there could be another A2DP device already connected in APM, but it
         // doesn't matter as this new one will overwrite the previous one
-        final int res = mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec);
+        final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name),
+                AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);
 
         // TODO: log in MediaMetrics once distinction between connection failure and
         // double connection is made.
@@ -1035,8 +1033,9 @@
 
         // device to remove was visible by APM, update APM
         mDeviceBroker.clearAvrcpAbsoluteVolumeSupported();
-        final int res = mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "", a2dpCodec);
+        final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, a2dpCodec);
 
         if (res != AudioSystem.AUDIO_STATUS_OK) {
             AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
@@ -1074,8 +1073,9 @@
 
     @GuardedBy("mDevicesLock")
     private void makeA2dpSrcAvailable(String address) {
-        mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, "",
+        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+                AudioSystem.DEVICE_STATE_AVAILABLE,
                 AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.put(
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
@@ -1085,8 +1085,9 @@
 
     @GuardedBy("mDevicesLock")
     private void makeA2dpSrcUnavailable(String address) {
-        mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+                AudioSystem.DEVICE_STATE_UNAVAILABLE,
                 AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.remove(
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
@@ -1099,8 +1100,9 @@
                 AudioSystem.DEVICE_OUT_HEARING_AID);
         mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
 
-        mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
-                AudioSystem.DEVICE_STATE_AVAILABLE, address, name,
+        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_HEARING_AID, address, name),
+                AudioSystem.DEVICE_STATE_AVAILABLE,
                 AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.put(
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
@@ -1122,8 +1124,9 @@
 
     @GuardedBy("mDevicesLock")
     private void makeHearingAidDeviceUnavailable(String address) {
-        mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+        mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_HEARING_AID, address),
+                AudioSystem.DEVICE_STATE_UNAVAILABLE,
                 AudioSystem.AUDIO_FORMAT_DEFAULT);
         mConnectedDevices.remove(
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
@@ -1140,14 +1143,14 @@
     private void makeLeAudioDeviceAvailable(String address, String name, int streamType, int device,
             String eventSource) {
         if (device != AudioSystem.DEVICE_NONE) {
-
             /* Audio Policy sees Le Audio similar to A2DP. Let's make sure
              * AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
              */
             mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
 
-            AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
-                    address, name, AudioSystem.AUDIO_FORMAT_DEFAULT);
+            AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(device, address, name),
+                    AudioSystem.DEVICE_STATE_AVAILABLE,
+                    AudioSystem.AUDIO_FORMAT_DEFAULT);
             mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
                     new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
             mDeviceBroker.postAccessoryPlugMediaUnmute(device);
@@ -1168,8 +1171,9 @@
     @GuardedBy("mDevicesLock")
     private void makeLeAudioDeviceUnavailable(String address, int device) {
         if (device != AudioSystem.DEVICE_NONE) {
-            AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
-                    address, "", AudioSystem.AUDIO_FORMAT_DEFAULT);
+            AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(device, address),
+                    AudioSystem.DEVICE_STATE_UNAVAILABLE,
+                    AudioSystem.AUDIO_FORMAT_DEFAULT);
             mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
         }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4494d96..05955c3 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6371,23 +6371,23 @@
     /**
      * see AudioManager.setWiredDeviceConnectionState()
      */
-    public void setWiredDeviceConnectionState(int type,
-            @ConnectionState int state, String address, String name,
-            String caller) {
+    public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
+            @ConnectionState int state, String caller) {
         enforceModifyAudioRoutingPermission();
         if (state != CONNECTION_STATE_CONNECTED
                 && state != CONNECTION_STATE_DISCONNECTED) {
             throw new IllegalArgumentException("Invalid state " + state);
         }
         new MediaMetrics.Item(mMetricsId + "setWiredDeviceConnectionState")
-                .set(MediaMetrics.Property.ADDRESS, address)
+                .set(MediaMetrics.Property.ADDRESS, attributes.getAddress())
                 .set(MediaMetrics.Property.CLIENT_NAME, caller)
-                .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(type))
-                .set(MediaMetrics.Property.NAME, name)
+                .set(MediaMetrics.Property.DEVICE,
+                        AudioSystem.getDeviceName(attributes.getInternalType()))
+                .set(MediaMetrics.Property.NAME, attributes.getName())
                 .set(MediaMetrics.Property.STATE,
                         state == CONNECTION_STATE_CONNECTED ? "connected" : "disconnected")
                 .record();
-        mDeviceBroker.setWiredDeviceConnectionState(type, state, address, name, caller);
+        mDeviceBroker.setWiredDeviceConnectionState(attributes, state, caller);
     }
 
     /** @see AudioManager#setTestDeviceConnectionState(AudioDeviceAttributes, boolean) */
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 3137fa5..3225274 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -116,10 +116,11 @@
         @Override
         public String eventToString() {
             return new StringBuilder("setWiredDeviceConnectionState(")
-                    .append(" type:").append(Integer.toHexString(mState.mType))
+                    .append(" type:").append(
+                            Integer.toHexString(mState.mAttributes.getInternalType()))
                     .append(" state:").append(AudioSystem.deviceStateToString(mState.mState))
-                    .append(" addr:").append(mState.mAddress)
-                    .append(" name:").append(mState.mName)
+                    .append(" addr:").append(mState.mAttributes.getAddress())
+                    .append(" name:").append(mState.mAttributes.getName())
                     .append(") from ").append(mState.mCaller).toString();
         }
     }
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index a2ba76b..f572261 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -258,19 +258,16 @@
     }
 
     /**
-     * Same as {@link AudioSystem#setDeviceConnectionState(int, int, String, String, int)}
-     * @param device
+     * Same as {@link AudioSystem#setDeviceConnectionState(AudioDeviceAttributes, int, int)}
+     * @param attributes
      * @param state
-     * @param deviceAddress
-     * @param deviceName
      * @param codecFormat
      * @return
      */
-    public int setDeviceConnectionState(int device, int state, String deviceAddress,
-                                        String deviceName, int codecFormat) {
+    public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+            int codecFormat) {
         invalidateRoutingCache();
-        return AudioSystem.setDeviceConnectionState(device, state, deviceAddress, deviceName,
-                codecFormat);
+        return AudioSystem.setDeviceConnectionState(attributes, state, codecFormat);
     }
 
     /**
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index a006b91..3491cd5 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -595,8 +595,9 @@
         String btDeviceName =  getName(btDevice);
         boolean result = false;
         if (isActive) {
-            result |= mDeviceBroker.handleDeviceConnection(isActive, audioDevice.getInternalType(),
-                    audioDevice.getAddress(), btDeviceName);
+            result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+                    audioDevice.getInternalType(), audioDevice.getAddress(), btDeviceName),
+                    isActive);
         } else {
             int[] outDeviceTypes = {
                     AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
@@ -604,13 +605,15 @@
                     AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
             };
             for (int outDeviceType : outDeviceTypes) {
-                result |= mDeviceBroker.handleDeviceConnection(
-                        isActive, outDeviceType, audioDevice.getAddress(), btDeviceName);
+                result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+                        outDeviceType, audioDevice.getAddress(), btDeviceName),
+                        isActive);
             }
         }
         // handleDeviceConnection() && result to make sure the method get executed
-        result = mDeviceBroker.handleDeviceConnection(
-                isActive, inDevice, audioDevice.getAddress(), btDeviceName) && result;
+        result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+                        inDevice, audioDevice.getAddress(), btDeviceName),
+                isActive) && result;
         return result;
     }
 
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 1b0341c..e0b768d 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -808,6 +808,7 @@
                     streamProtos[i].histogramBins = streamStats.getHistogramBins();
                     streamProtos[i].histogramCounts = streamStats.getHistogramCounts();
                     streamProtos[i].dynamicRangeProfile = streamStats.getDynamicRangeProfile();
+                    streamProtos[i].streamUseCase = streamStats.getStreamUseCase();
 
                     if (CameraServiceProxy.DEBUG) {
                         String histogramTypeName =
@@ -828,7 +829,8 @@
                                 + Arrays.toString(streamProtos[i].histogramBins)
                                 + ", histogramCounts "
                                 + Arrays.toString(streamProtos[i].histogramCounts)
-                                + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile);
+                                + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile
+                                + ", streamUseCase " + streamProtos[i].streamUseCase);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 53fe450..eb2f80b 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -722,7 +722,7 @@
                         clipboard.primaryClipListeners.getBroadcastItem(i)
                                 .dispatchPrimaryClipChanged();
                     }
-                } catch (RemoteException e) {
+                } catch (RemoteException | SecurityException e) {
                     // The RemoteCallbackList will take care of removing
                     // the dead object for us.
                 }
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index a1d722b..c46ae85 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -69,8 +69,10 @@
      */
     @Nullable
     public static BrightnessMappingStrategy create(Resources resources,
-            DisplayDeviceConfig displayDeviceConfig) {
-        return create(resources, displayDeviceConfig, /* isForIdleMode= */ false, null);
+            DisplayDeviceConfig displayDeviceConfig,
+            DisplayWhiteBalanceController displayWhiteBalanceController) {
+        return create(resources, displayDeviceConfig, /* isForIdleMode= */ false,
+                displayWhiteBalanceController);
     }
 
     /**
@@ -845,7 +847,7 @@
             float nits = mBrightnessSpline.interpolate(lux);
 
             // Adjust nits to compensate for display white balance colour strength.
-            if (mDisplayWhiteBalanceController != null && isForIdleMode()) {
+            if (mDisplayWhiteBalanceController != null) {
                 nits = mDisplayWhiteBalanceController.calculateAdjustedBrightnessNits(nits);
             }
 
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index a4a6eb4..6866137 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -30,6 +30,8 @@
 import android.util.Spline;
 import android.view.DisplayAddress;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import com.android.internal.R;
 import com.android.internal.display.BrightnessSynchronizer;
 import com.android.server.display.config.BrightnessThresholds;
@@ -40,9 +42,12 @@
 import com.android.server.display.config.DisplayQuirks;
 import com.android.server.display.config.HbmTiming;
 import com.android.server.display.config.HighBrightnessMode;
+import com.android.server.display.config.Interpolation;
 import com.android.server.display.config.NitsMap;
 import com.android.server.display.config.Point;
 import com.android.server.display.config.RefreshRateRange;
+import com.android.server.display.config.SdrHdrRatioMap;
+import com.android.server.display.config.SdrHdrRatioPoint;
 import com.android.server.display.config.SensorDetails;
 import com.android.server.display.config.ThermalStatus;
 import com.android.server.display.config.ThermalThrottling;
@@ -66,10 +71,126 @@
 import javax.xml.datatype.DatatypeConfigurationException;
 
 /**
- * Reads and stores display-specific configurations.
+ *  Reads and stores display-specific configurations.
+ *  File format:
+ *  <pre>
+ *  {@code
+ *    <displayConfiguration>
+ *      <densityMap>
+ *        <density>
+ *          <height>480</height>
+ *          <width>720</width>
+ *          <density>120</density>
+ *        </density>
+ *        <density>
+ *          <height>720</height>
+ *          <width>1280</width>
+ *          <density>213</density>
+ *        </density>
+ *        <density>
+ *          <height>1080</height>
+ *          <width>1920</width>
+ *          <density>320</density>
+ *        </density>
+ *        <density>
+ *          <height>2160</height>
+ *          <width>3840</width>
+ *          <density>640</density>
+ *        </density>
+ *      </densityMap>
+ *
+ *      <screenBrightnessMap>
+ *        <point>
+ *          <value>0.0</value>
+ *          <nits>2.0</nits>
+ *        </point>
+ *        <point>
+ *          <value>0.62</value>
+ *          <nits>500.0</nits>
+ *        </point>
+ *        <point>
+ *          <value>1.0</value>
+ *          <nits>800.0</nits>
+ *        </point>
+ *      </screenBrightnessMap>
+ *
+ *      <screenBrightnessDefault>0.65</screenBrightnessDefault>
+ *
+ *      <thermalThrottling>
+ *        <brightnessThrottlingMap>
+ *          <brightnessThrottlingPoint>
+ *            <thermalStatus>severe</thermalStatus>
+ *            <brightness>0.1</brightness>
+ *          </brightnessThrottlingPoint>
+ *          <brightnessThrottlingPoint>
+ *            <thermalStatus>critical</thermalStatus>
+ *            <brightness>0.01</brightness>
+ *          </brightnessThrottlingPoint>
+ *        </brightnessThrottlingMap>
+ *      </thermalThrottling>
+ *
+ *      <highBrightnessMode enabled="true">
+ *        <transitionPoint>0.62</transitionPoint>
+ *        <minimumLux>10000</minimumLux>
+ *        <timing>
+ *          <timeWindowSecs>1800</timeWindowSecs> // Window in which we restrict HBM.
+ *          <timeMaxSecs>300</timeMaxSecs>        // Maximum time of HBM allowed in that window.
+ *          <timeMinSecs>60</timeMinSecs>         // Minimum time remaining required to switch
+ *        </timing>                               //   HBM on for.
+ *        <refreshRate>
+ *          <minimum>120</minimum>
+ *          <maximum>120</maximum>
+ *        </refreshRate>
+ *        <thermalStatusLimit>light</thermalStatusLimit>
+ *        <allowInLowPowerMode>false</allowInLowPowerMode>
+ *      </highBrightnessMode>
+ *
+ *      <quirks>
+ *       <quirk>canSetBrightnessViaHwc</quirk>
+ *      </quirks>
+ *
+ *      <screenBrightnessRampFastDecrease>0.01</screenBrightnessRampFastDecrease>
+ *      <screenBrightnessRampFastIncrease>0.02</screenBrightnessRampFastIncrease>
+ *      <screenBrightnessRampSlowDecrease>0.03</screenBrightnessRampSlowDecrease>
+ *      <screenBrightnessRampSlowIncrease>0.04</screenBrightnessRampSlowIncrease>
+ *
+ *      <lightSensor>
+ *        <type>android.sensor.light</type>
+ *        <name>1234 Ambient Light Sensor</name>
+ *      </lightSensor>
+ *      <proxSensor>
+ *        <type>android.sensor.proximity</type>
+ *        <name>1234 Proximity Sensor</name>
+ *      </proxSensor>
+ *
+ *      <ambientLightHorizonLong>10001</ambientLightHorizonLong>
+ *      <ambientLightHorizonShort>2001</ambientLightHorizonShort>
+ *
+ *      <displayBrightnessChangeThresholds>
+ *        <brighteningThresholds>
+ *          <minimum>0.001</minimum>  // Minimum change needed in screen brightness to brighten.
+ *        </brighteningThresholds>
+ *        <darkeningThresholds>
+ *          <minimum>0.002</minimum>  // Minimum change needed in screen brightness to darken.
+ *        </darkeningThresholds>
+ *      </displayBrightnessChangeThresholds>
+ *
+ *      <ambientBrightnessChangeThresholds>
+ *        <brighteningThresholds>
+ *          <minimum>0.003</minimum>  // Minimum change needed in ambient brightness to brighten.
+ *        </brighteningThresholds>
+ *        <darkeningThresholds>
+ *          <minimum>0.004</minimum>  // Minimum change needed in ambient brightness to darken.
+ *        </darkeningThresholds>
+ *      </ambientBrightnessChangeThresholds>
+ *
+ *    </displayConfiguration>
+ *  }
+ *  </pre>
  */
 public class DisplayDeviceConfig {
     private static final String TAG = "DisplayDeviceConfig";
+    private static final boolean DEBUG = false;
 
     public static final float HIGH_BRIGHTNESS_MODE_UNSUPPORTED = Float.NaN;
 
@@ -86,6 +207,9 @@
     private static final String NO_SUFFIX_FORMAT = "%d";
     private static final long STABLE_FLAG = 1L << 62;
 
+    private static final int INTERPOLATION_DEFAULT = 0;
+    private static final int INTERPOLATION_LINEAR = 1;
+
     // Float.NaN (used as invalid for brightness) cannot be stored in config.xml
     // so -2 is used instead
     private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f;
@@ -99,6 +223,9 @@
     // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
     private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
 
+    @VisibleForTesting
+    static final float HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT = 0.5f;
+
     private final Context mContext;
 
     // The details of the ambient light sensor associated with this display.
@@ -114,6 +241,7 @@
     // config.xml. These are the raw values and just used for the dumpsys
     private float[] mRawNits;
     private float[] mRawBacklight;
+    private int mInterpolationType;
 
     // These arrays are calculated from the raw arrays, but clamped to contain values equal to and
     // between mBacklightMinimum and mBacklightMaximum. These three arrays should all be the same
@@ -142,6 +270,7 @@
     private Spline mBrightnessToBacklightSpline;
     private Spline mBacklightToBrightnessSpline;
     private Spline mBacklightToNitsSpline;
+    private Spline mNitsToBacklightSpline;
     private List<String> mQuirks;
     private boolean mIsHighBrightnessModeEnabled = false;
     private HighBrightnessModeData mHbmData;
@@ -149,6 +278,7 @@
     private String mLoadedFrom = null;
 
     private BrightnessThrottlingData mBrightnessThrottlingData;
+    private Spline mSdrToHdrRatioSpline;
 
     private DisplayDeviceConfig(Context context) {
         mContext = context;
@@ -333,6 +463,45 @@
     }
 
     /**
+     * Calculate the HDR brightness for the specified SDR brightenss.
+     *
+     * @return the HDR brightness or BRIGHTNESS_INVALID when no mapping exists.
+     */
+    public float getHdrBrightnessFromSdr(float brightness) {
+        if (mSdrToHdrRatioSpline == null) {
+            return PowerManager.BRIGHTNESS_INVALID;
+        }
+
+        float backlight = getBacklightFromBrightness(brightness);
+        float nits = getNitsFromBacklight(backlight);
+        if (nits == NITS_INVALID) {
+            return PowerManager.BRIGHTNESS_INVALID;
+        }
+
+        float ratio = mSdrToHdrRatioSpline.interpolate(nits);
+        float hdrNits = nits * ratio;
+        if (mNitsToBacklightSpline == null) {
+            return PowerManager.BRIGHTNESS_INVALID;
+        }
+
+        float hdrBacklight = mNitsToBacklightSpline.interpolate(hdrNits);
+        hdrBacklight = Math.max(mBacklightMinimum, Math.min(mBacklightMaximum, hdrBacklight));
+        float hdrBrightness = mBacklightToBrightnessSpline.interpolate(hdrBacklight);
+
+        if (DEBUG) {
+            Slog.d(TAG, "getHdrBrightnessFromSdr: sdr brightness " + brightness
+                + " backlight " + backlight
+                + " nits " + nits
+                + " ratio " + ratio
+                + " hdrNits " + hdrNits
+                + " hdrBacklight " + hdrBacklight
+                + " hdrBrightness " + hdrBrightness
+                );
+        }
+        return hdrBrightness;
+    }
+
+    /**
      * Return an array of equal length to backlight and nits, that covers the entire system
      * brightness range of 0.0-1.0.
      *
@@ -444,15 +613,18 @@
                 + ", mNits=" + Arrays.toString(mNits)
                 + ", mRawBacklight=" + Arrays.toString(mRawBacklight)
                 + ", mRawNits=" + Arrays.toString(mRawNits)
+                + ", mInterpolationType=" + mInterpolationType
                 + ", mBrightness=" + Arrays.toString(mBrightness)
                 + ", mBrightnessToBacklightSpline=" + mBrightnessToBacklightSpline
                 + ", mBacklightToBrightnessSpline=" + mBacklightToBrightnessSpline
+                + ", mNitsToBacklightSpline=" + mNitsToBacklightSpline
                 + ", mBacklightMinimum=" + mBacklightMinimum
                 + ", mBacklightMaximum=" + mBacklightMaximum
                 + ", mBrightnessDefault=" + mBrightnessDefault
                 + ", mQuirks=" + mQuirks
                 + ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
                 + ", mHbmData=" + mHbmData
+                + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
                 + ", mBrightnessThrottlingData=" + mBrightnessThrottlingData
                 + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
                 + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
@@ -653,6 +825,7 @@
         float[] nits = new float[size];
         float[] backlight = new float[size];
 
+        mInterpolationType = convertInterpolationType(map.getInterpolation());
         int i = 0;
         for (Point point : points) {
             nits[i] = point.getNits().floatValue();
@@ -678,6 +851,40 @@
         constrainNitsAndBacklightArrays();
     }
 
+    private Spline loadSdrHdrRatioMap(HighBrightnessMode hbmConfig) {
+        final SdrHdrRatioMap sdrHdrRatioMap = hbmConfig.getSdrHdrRatioMap_all();
+
+        if (sdrHdrRatioMap == null) {
+            return null;
+        }
+
+        final List<SdrHdrRatioPoint> points = sdrHdrRatioMap.getPoint();
+        final int size = points.size();
+        if (size <= 0) {
+            return null;
+        }
+
+        float[] nits = new float[size];
+        float[] ratios = new float[size];
+
+        int i = 0;
+        for (SdrHdrRatioPoint point : points) {
+            nits[i] = point.getSdrNits().floatValue();
+            if (i > 0) {
+                if (nits[i] < nits[i - 1]) {
+                    Slog.e(TAG, "sdrHdrRatioMap must be non-decreasing, ignoring rest "
+                                + " of configuration. nits: " + nits[i] + " < "
+                                + nits[i - 1]);
+                    return null;
+                }
+            }
+            ratios[i] = point.getHdrRatio().floatValue();
+            ++i;
+        }
+
+        return Spline.createSpline(nits, ratios);
+    }
+
     private void loadBrightnessThrottlingMap(DisplayConfiguration config) {
         final ThermalThrottling throttlingConfig = config.getThermalThrottling();
         if (throttlingConfig == null) {
@@ -823,9 +1030,18 @@
                     mBacklight[mBacklight.length - 1],
                     PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, mBacklight[i]);
         }
-        mBrightnessToBacklightSpline = Spline.createSpline(mBrightness, mBacklight);
-        mBacklightToBrightnessSpline = Spline.createSpline(mBacklight, mBrightness);
-        mBacklightToNitsSpline = Spline.createSpline(mBacklight, mNits);
+        mBrightnessToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
+            ? Spline.createLinearSpline(mBrightness, mBacklight)
+            : Spline.createSpline(mBrightness, mBacklight);
+        mBacklightToBrightnessSpline = mInterpolationType == INTERPOLATION_LINEAR
+            ? Spline.createLinearSpline(mBacklight, mBrightness)
+            : Spline.createSpline(mBacklight, mBrightness);
+        mBacklightToNitsSpline = mInterpolationType == INTERPOLATION_LINEAR
+            ? Spline.createLinearSpline(mBacklight, mNits)
+            : Spline.createSpline(mBacklight, mNits);
+        mNitsToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
+            ? Spline.createLinearSpline(mNits, mBacklight)
+            : Spline.createSpline(mNits, mBacklight);
     }
 
     private void loadQuirks(DisplayConfiguration config) {
@@ -862,6 +1078,20 @@
                 mRefreshRateLimitations.add(new RefreshRateLimitation(
                         DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max));
             }
+            BigDecimal minHdrPctOfScreen = hbm.getMinimumHdrPercentOfScreen_all();
+            if (minHdrPctOfScreen != null) {
+                mHbmData.minimumHdrPercentOfScreen = minHdrPctOfScreen.floatValue();
+                if (mHbmData.minimumHdrPercentOfScreen > 1
+                        || mHbmData.minimumHdrPercentOfScreen < 0) {
+                    Slog.w(TAG, "Invalid minimum HDR percent of screen: "
+                                    + String.valueOf(mHbmData.minimumHdrPercentOfScreen));
+                    mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+                }
+            } else {
+                mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+            }
+
+            mSdrToHdrRatioSpline = loadSdrHdrRatioMap(hbm);
         }
     }
 
@@ -1024,6 +1254,21 @@
         }
     }
 
+    private int convertInterpolationType(Interpolation value) {
+        if (value == null) {
+            return INTERPOLATION_DEFAULT;
+        }
+        switch (value) {
+            case _default:
+                return INTERPOLATION_DEFAULT;
+            case linear:
+                return INTERPOLATION_LINEAR;
+            default:
+                Slog.wtf(TAG, "Unexpected Interpolation Type: " + value);
+                return INTERPOLATION_DEFAULT;
+        }
+    }
+
     private void loadAmbientHorizonFromDdc(DisplayConfiguration config) {
         final BigInteger configLongHorizon = config.getAmbientLightHorizonLong();
         if (configLongHorizon != null) {
@@ -1088,11 +1333,15 @@
         /** Minimum time that HBM can be on before being enabled. */
         public long timeMinMillis;
 
+        /** Minimum HDR video size to enter high brightness mode */
+        public float minimumHdrPercentOfScreen;
+
         HighBrightnessModeData() {}
 
         HighBrightnessModeData(float minimumLux, float transitionPoint, long timeWindowMillis,
                 long timeMaxMillis, long timeMinMillis,
-                @PowerManager.ThermalStatus int thermalStatusLimit, boolean allowInLowPowerMode) {
+                @PowerManager.ThermalStatus int thermalStatusLimit, boolean allowInLowPowerMode,
+                float minimumHdrPercentOfScreen) {
             this.minimumLux = minimumLux;
             this.transitionPoint = transitionPoint;
             this.timeWindowMillis = timeWindowMillis;
@@ -1100,6 +1349,7 @@
             this.timeMinMillis = timeMinMillis;
             this.thermalStatusLimit = thermalStatusLimit;
             this.allowInLowPowerMode = allowInLowPowerMode;
+            this.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
         }
 
         /**
@@ -1114,6 +1364,7 @@
             other.transitionPoint = transitionPoint;
             other.thermalStatusLimit = thermalStatusLimit;
             other.allowInLowPowerMode = allowInLowPowerMode;
+            other.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
         }
 
         @Override
@@ -1126,6 +1377,7 @@
                     + ", timeMin: " + timeMinMillis + "ms"
                     + ", thermalStatusLimit: " + thermalStatusLimit
                     + ", allowInLowPowerMode: " + allowInLowPowerMode
+                    + ", minimumHdrPercentOfScreen: " + minimumHdrPercentOfScreen
                     + "} ";
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 6ae1a5a..d71e07a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -546,28 +546,6 @@
         // Seed the cached brightness
         saveBrightnessInfo(getScreenBrightnessSetting());
 
-        setUpAutoBrightness(resources, handler);
-
-        mColorFadeEnabled = !ActivityManager.isLowRamDeviceStatic();
-        mColorFadeFadesConfig = resources.getBoolean(
-                com.android.internal.R.bool.config_animateScreenLights);
-
-        mDisplayBlanksAfterDozeConfig = resources.getBoolean(
-                com.android.internal.R.bool.config_displayBlanksAfterDoze);
-
-        mBrightnessBucketsInDozeConfig = resources.getBoolean(
-                com.android.internal.R.bool.config_displayBrightnessBucketsInDoze);
-
-        loadProximitySensor();
-
-        mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
-        mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
-        mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
-        mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-        mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-        mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-        mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-
         DisplayWhiteBalanceSettings displayWhiteBalanceSettings = null;
         DisplayWhiteBalanceController displayWhiteBalanceController = null;
         if (mDisplayId == Display.DEFAULT_DISPLAY) {
@@ -610,6 +588,29 @@
         } else {
             mCdsi = null;
         }
+
+        setUpAutoBrightness(resources, handler);
+
+        mColorFadeEnabled = !ActivityManager.isLowRamDeviceStatic();
+        mColorFadeFadesConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_animateScreenLights);
+
+        mDisplayBlanksAfterDozeConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_displayBlanksAfterDoze);
+
+        mBrightnessBucketsInDozeConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_displayBrightnessBucketsInDoze);
+
+        loadProximitySensor();
+
+        mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
+        mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
+        mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
+        mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+
     }
 
     private void applyReduceBrightColorsSplineAdjustment(
@@ -831,7 +832,13 @@
         setUpAutoBrightness(mContext.getResources(), mHandler);
         reloadReduceBrightColours();
         mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
-                mDisplayDeviceConfig.getHighBrightnessModeData());
+                mDisplayDeviceConfig.getHighBrightnessModeData(),
+                new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
+                    @Override
+                    public float getHdrBrightnessFromSdr(float sdrBrightness) {
+                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
+                    }
+                });
         mBrightnessThrottler.resetThrottlingData(
                 mDisplayDeviceConfig.getBrightnessThrottlingData());
     }
@@ -901,7 +908,7 @@
         final boolean isIdleScreenBrightnessEnabled = resources.getBoolean(
                 R.bool.config_enableIdleScreenBrightnessMode);
         mInteractiveModeBrightnessMapper = BrightnessMappingStrategy.create(resources,
-                mDisplayDeviceConfig);
+                mDisplayDeviceConfig, mDisplayWhiteBalanceController);
         if (isIdleScreenBrightnessEnabled) {
             mIdleModeBrightnessMapper = BrightnessMappingStrategy.createForIdleMode(resources,
                     mDisplayDeviceConfig, mDisplayWhiteBalanceController);
@@ -1713,6 +1720,12 @@
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         return new HighBrightnessModeController(mHandler, info.width, info.height, displayToken,
                 displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
+                new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
+                    @Override
+                    public float getHdrBrightnessFromSdr(float sdrBrightness) {
+                        return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
+                    }
+                },
                 () -> {
                     sendUpdatePowerStateLocked();
                     postBrightnessChangeRunnable();
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 23c17f5..0b9d4de 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -58,11 +58,13 @@
 
     private static final boolean DEBUG = false;
 
-    private static final float HDR_PERCENT_OF_SCREEN_REQUIRED = 0.50f;
-
     @VisibleForTesting
     static final float HBM_TRANSITION_POINT_INVALID = Float.POSITIVE_INFINITY;
 
+    public interface HdrBrightnessDeviceConfig {
+        float getHdrBrightnessFromSdr(float sdrBrightness);
+    }
+
     private final float mBrightnessMin;
     private final float mBrightnessMax;
     private final Handler mHandler;
@@ -76,6 +78,7 @@
 
     private HdrListener mHdrListener;
     private HighBrightnessModeData mHbmData;
+    private HdrBrightnessDeviceConfig mHdrBrightnessCfg;
     private IBinder mRegisteredDisplayToken;
 
     private boolean mIsInAllowedAmbientRange = false;
@@ -115,16 +118,17 @@
 
     HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken,
             String displayUniqueId, float brightnessMin, float brightnessMax,
-            HighBrightnessModeData hbmData, Runnable hbmChangeCallback, Context context) {
+            HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
+            Runnable hbmChangeCallback, Context context) {
         this(new Injector(), handler, width, height, displayToken, displayUniqueId, brightnessMin,
-            brightnessMax, hbmData, hbmChangeCallback, context);
+            brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, context);
     }
 
     @VisibleForTesting
     HighBrightnessModeController(Injector injector, Handler handler, int width, int height,
             IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax,
-            HighBrightnessModeData hbmData, Runnable hbmChangeCallback,
-            Context context) {
+            HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
+            Runnable hbmChangeCallback, Context context) {
         mInjector = injector;
         mContext = context;
         mClock = injector.getClock();
@@ -138,7 +142,7 @@
         mRecalcRunnable = this::recalculateTimeAllowance;
         mHdrListener = new HdrListener();
 
-        resetHbmData(width, height, displayToken, displayUniqueId, hbmData);
+        resetHbmData(width, height, displayToken, displayUniqueId, hbmData, hdrBrightnessCfg);
     }
 
     void setAutoBrightnessEnabled(int state) {
@@ -178,6 +182,13 @@
     }
 
     float getHdrBrightnessValue() {
+        if (mHdrBrightnessCfg != null) {
+            float hdrBrightness = mHdrBrightnessCfg.getHdrBrightnessFromSdr(mBrightness);
+            if (hdrBrightness != PowerManager.BRIGHTNESS_INVALID) {
+                return hdrBrightness;
+            }
+        }
+
         // For HDR brightness, we take the current brightness and scale it to the max. The reason
         // we do this is because we want brightness to go to HBM max when it would normally go
         // to normal max, meaning it should not wait to go to 10000 lux (or whatever the transition
@@ -250,10 +261,11 @@
     }
 
     void resetHbmData(int width, int height, IBinder displayToken, String displayUniqueId,
-            HighBrightnessModeData hbmData) {
+            HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg) {
         mWidth = width;
         mHeight = height;
         mHbmData = hbmData;
+        mHdrBrightnessCfg = hdrBrightnessCfg;
         mDisplayStatsId = displayUniqueId.hashCode();
 
         unregisterHdrListener();
@@ -602,8 +614,8 @@
                 int maxW, int maxH, int flags) {
             mHandler.post(() -> {
                 mIsHdrLayerPresent = numberOfHdrLayers > 0
-                        && (float) (maxW * maxH)
-                                >= ((float) (mWidth * mHeight) * HDR_PERCENT_OF_SCREEN_REQUIRED);
+                        && (float) (maxW * maxH) >= ((float) (mWidth * mHeight)
+                                   * mHbmData.minimumHdrPercentOfScreen);
                 // Calling the brightness update so that we can recalculate
                 // brightness with HDR in mind.
                 onBrightnessChanged(mBrightness, mUnthrottledBrightness, mThrottlingReason);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index afcd3dd..1ce36b1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -41,7 +41,10 @@
 import android.hardware.hdmi.HdmiTimerRecordSources;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
-import android.media.AudioSystem;
+import android.media.AudioDescriptor;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioProfile;
 import android.media.tv.TvInputInfo;
 import android.media.tv.TvInputManager.TvInputCallback;
 import android.util.Slog;
@@ -58,6 +61,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Represent a logical device of type TV residing in Android system.
@@ -816,12 +820,23 @@
 
         HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
         boolean oldStatus = mArcEstablished;
-        // 1. Enable/disable ARC circuit.
-        enableAudioReturnChannel(enabled);
-        // 2. Notify arc status to audio service.
-        notifyArcStatusToAudioService(enabled);
-        // 3. Update arc status;
-        mArcEstablished = enabled;
+        if (enabled) {
+            RequestSadAction action = new RequestSadAction(
+                    this, Constants.ADDR_AUDIO_SYSTEM,
+                    new RequestSadAction.RequestSadCallback() {
+                        @Override
+                        public void onRequestSadDone(List<byte[]> supportedSads) {
+                            enableAudioReturnChannel(enabled);
+                            notifyArcStatusToAudioService(enabled, supportedSads);
+                            mArcEstablished = enabled;
+                        }
+                    });
+            addAndStartAction(action);
+        } else {
+            enableAudioReturnChannel(enabled);
+            notifyArcStatusToAudioService(enabled, new ArrayList<>());
+            mArcEstablished = enabled;
+        }
         return oldStatus;
     }
 
@@ -843,11 +858,15 @@
         return mService.isConnected(portId);
     }
 
-    private void notifyArcStatusToAudioService(boolean enabled) {
+    private void notifyArcStatusToAudioService(boolean enabled, List<byte[]> supportedSads) {
         // Note that we don't set any name to ARC.
-        mService.getAudioManager().setWiredDeviceConnectionState(
-                AudioSystem.DEVICE_OUT_HDMI_ARC,
-                enabled ? 1 : 0, "", "");
+        AudioDeviceAttributes attributes = new AudioDeviceAttributes(
+                AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_ARC, "", "",
+                new ArrayList<AudioProfile>(), supportedSads.stream()
+                .map(sad -> new AudioDescriptor(AudioDescriptor.STANDARD_EDID,
+                        AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, sad))
+                .collect(Collectors.toList()));
+        mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);
     }
 
     /**
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bfaa7b3..940c25c 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -41,7 +41,6 @@
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
 import android.graphics.PointF;
-import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayViewport;
 import android.hardware.input.IInputDevicesChangedListener;
@@ -64,6 +63,7 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IInputConstants;
 import android.os.IVibratorStateListener;
 import android.os.InputEventInjectionResult;
 import android.os.InputEventInjectionSync;
@@ -150,8 +150,6 @@
     static final String TAG = "InputManager";
     static final boolean DEBUG = false;
 
-    private static final boolean USE_SPY_WINDOW_GESTURE_MONITORS = true;
-
     private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
     private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";
 
@@ -198,8 +196,9 @@
 
     private final Object mTabletModeLock = new Object();
     // List of currently registered tablet mode changed listeners by process id
+    @GuardedBy("mTabletModeLock")
     private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
-            new SparseArray<>(); // guarded by mTabletModeLock
+            new SparseArray<>();
     private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
             new ArrayList<>();
 
@@ -217,40 +216,39 @@
     private final PersistentDataStore mDataStore = new PersistentDataStore();
 
     // List of currently registered input devices changed listeners by process id.
-    private Object mInputDevicesLock = new Object();
+    private final Object mInputDevicesLock = new Object();
     @GuardedBy("mInputDevicesLock")
-    private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
+    private boolean mInputDevicesChangedPending;
     @GuardedBy("mInputDevicesLock")
     private InputDevice[] mInputDevices = new InputDevice[0];
+    @GuardedBy("mInputDevicesLock")
     private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
-            new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
+            new SparseArray<>();
     private final ArrayList<InputDevicesChangedListenerRecord>
-            mTempInputDevicesChangedListenersToNotify =
-                    new ArrayList<InputDevicesChangedListenerRecord>(); // handler thread only
-    private final ArrayList<InputDevice>
-            mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
+            mTempInputDevicesChangedListenersToNotify = new ArrayList<>(); // handler thread only
+    private final ArrayList<InputDevice> mTempFullKeyboards =
+            new ArrayList<>(); // handler thread only
     private boolean mKeyboardLayoutNotificationShown;
     private Toast mSwitchedKeyboardLayoutToast;
 
     // State for vibrator tokens.
-    private Object mVibratorLock = new Object();
-    private Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<IBinder, VibratorToken>();
+    private final Object mVibratorLock = new Object();
+    private final Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<>();
     private int mNextVibratorTokenValue;
 
     // List of currently registered vibrator state changed listeners by device id.
     @GuardedBy("mVibratorLock")
     private final SparseArray<RemoteCallbackList<IVibratorStateListener>> mVibratorStateListeners =
-            new SparseArray<RemoteCallbackList<IVibratorStateListener>>();
+            new SparseArray<>();
     // List of vibrator states by device id.
     @GuardedBy("mVibratorLock")
     private final SparseBooleanArray mIsVibrating = new SparseBooleanArray();
-    private Object mLightLock = new Object();
+    private final Object mLightLock = new Object();
     // State for light tokens. A light token marks a lights manager session, it is generated
     // by light session open() and deleted in session close().
     // When lights session requests light states, the token will be used to find the light session.
     @GuardedBy("mLightLock")
-    private final ArrayMap<IBinder, LightSession> mLightSessions =
-            new ArrayMap<IBinder, LightSession>();
+    private final ArrayMap<IBinder, LightSession> mLightSessions = new ArrayMap<>();
 
     // State for lid switch
     // Lock for the lid switch state. Held when triggering callbacks to guarantee lid switch events
@@ -259,25 +257,36 @@
     // events that occur at the same time are delivered after the callback has returned.
     private final Object mLidSwitchLock = new Object();
     @GuardedBy("mLidSwitchLock")
-    private List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>();
+    private final List<LidSwitchCallback> mLidSwitchCallbacks = new ArrayList<>();
 
     // State for the currently installed input filter.
     final Object mInputFilterLock = new Object();
-    IInputFilter mInputFilter; // guarded by mInputFilterLock
-    InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
+    @GuardedBy("mInputFilterLock")
+    IInputFilter mInputFilter;
+    @GuardedBy("mInputFilterLock")
+    InputFilterHost mInputFilterHost;
 
     // The associations of input devices to displays by port. Maps from input device port (String)
     // to display id (int). Currently only accessed by InputReader.
     private final Map<String, Integer> mStaticAssociations;
     private final Object mAssociationsLock = new Object();
     @GuardedBy("mAssociationLock")
-    private final Map<String, Integer> mRuntimeAssociations = new ArrayMap<String, Integer>();
+    private final Map<String, Integer> mRuntimeAssociations = new ArrayMap<>();
     @GuardedBy("mAssociationLock")
     private final Map<String, String> mUniqueIdAssociations = new ArrayMap<>();
-    private final Object mPointerDisplayIdLock = new Object();
+
+    private final Object mAdditionalDisplayInputPropertiesLock = new Object();
+
     // Forces the MouseCursorController to target a specific display id.
-    @GuardedBy("mPointerDisplayIdLock")
+    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
     private int mOverriddenPointerDisplayId = Display.INVALID_DISPLAY;
+    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
+    private final SparseArray<AdditionalDisplayInputProperties> mAdditionalDisplayInputProperties =
+            new SparseArray<>();
+    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
+    private int mIconType = PointerIcon.TYPE_NOT_SPECIFIED;
+    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
+    private PointerIcon mIcon;
 
 
     // Holds all the registered gesture monitors that are implemented as spy windows. The spy
@@ -303,11 +312,12 @@
             int locationKeyCode);
     private static native InputChannel nativeCreateInputChannel(long ptr, String name);
     private static native InputChannel nativeCreateInputMonitor(long ptr, int displayId,
-            boolean isGestureMonitor, String name, int pid);
+            String name, int pid);
     private static native void nativeRemoveInputChannel(long ptr, IBinder connectionToken);
     private static native void nativePilferPointers(long ptr, IBinder token);
     private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
-    private static native void nativeSetInTouchMode(long ptr, boolean inTouchMode);
+    private static native boolean nativeSetInTouchMode(long ptr, boolean inTouchMode, int pid,
+            int uid, boolean hasPermission);
     private static native void nativeSetMaximumObscuringOpacityForTouch(long ptr, float opacity);
     private static native void nativeSetBlockUntrustedTouchesMode(long ptr, int mode);
     private static native int nativeInjectInputEvent(long ptr, InputEvent event,
@@ -582,38 +592,27 @@
         nativeReloadDeviceAliases(mPtr);
     }
 
-    /** Rotates CCW by `delta` 90-degree increments. */
-    private static void rotateBounds(Rect inOutBounds, int parentW, int parentH, int delta) {
-        int rdelta = ((delta % 4) + 4) % 4;
-        int origLeft = inOutBounds.left;
-        switch (rdelta) {
-            case 0:
-                return;
-            case 1:
-                inOutBounds.left = inOutBounds.top;
-                inOutBounds.top = parentW - inOutBounds.right;
-                inOutBounds.right = inOutBounds.bottom;
-                inOutBounds.bottom = parentW - origLeft;
-                return;
-            case 2:
-                inOutBounds.left = parentW - inOutBounds.right;
-                inOutBounds.right = parentW - origLeft;
-                return;
-            case 3:
-                inOutBounds.left = parentH - inOutBounds.bottom;
-                inOutBounds.bottom = inOutBounds.right;
-                inOutBounds.right = parentH - inOutBounds.top;
-                inOutBounds.top = origLeft;
-                return;
-        }
-    }
-
     private void setDisplayViewportsInternal(List<DisplayViewport> viewports) {
-        final DisplayViewport[] vArray = new DisplayViewport[viewports.size()];
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            final DisplayViewport[] vArray = new DisplayViewport[viewports.size()];
             for (int i = viewports.size() - 1; i >= 0; --i) {
                 vArray[i] = viewports.get(i);
             }
-        nativeSetDisplayViewports(mPtr, vArray);
+            nativeSetDisplayViewports(mPtr, vArray);
+
+            if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
+                final AdditionalDisplayInputProperties properties =
+                        mAdditionalDisplayInputProperties.get(mOverriddenPointerDisplayId);
+                if (properties != null) {
+                    updatePointerIconVisibleLocked(properties.pointerIconVisible);
+                    updatePointerAccelerationLocked(properties.pointerAcceleration);
+                    return;
+                }
+            }
+            updatePointerIconVisibleLocked(
+                    AdditionalDisplayInputProperties.DEFAULT_POINTER_ICON_VISIBLE);
+            updatePointerAccelerationLocked(IInputConstants.DEFAULT_POINTER_ACCELERATION);
+        }
     }
 
     /**
@@ -720,8 +719,7 @@
             throw new IllegalArgumentException("displayId must >= 0.");
         }
 
-        return nativeCreateInputMonitor(mPtr, displayId, false /* isGestureMonitor */,
-                inputChannelName, Binder.getCallingPid());
+        return nativeCreateInputMonitor(mPtr, displayId, inputChannelName, Binder.getCallingPid());
     }
 
     @NonNull
@@ -790,10 +788,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             final InputChannel inputChannel =
-                    USE_SPY_WINDOW_GESTURE_MONITORS
-                            ? createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid)
-                            : nativeCreateInputMonitor(mPtr, displayId, true /*isGestureMonitor*/,
-                                    requestedName, pid);
+                            createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid);
             return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken()));
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -872,12 +867,16 @@
      * other apps, when they become focused.
      *
      * When input dispatches focus to the apps, the touch mode state
-     * will be sent together with the focus change.
+     * will be sent together with the focus change (but each one in its own event).
      *
-     * @param inTouchMode true if the device is in touch mode.
+     * @param inTouchMode true if the device is in touch mode
+     * @param pid the pid of the process that requested to switch touch mode state
+     * @param uid the uid of the process that requested to switch touch mode state
+     * @param hasPermission if set to {@code true} then no further authorization will be performed
+     * @return {@code true} if the touch mode was successfully changed, {@code false} otherwise
      */
-    public void setInTouchMode(boolean inTouchMode) {
-        nativeSetInTouchMode(mPtr, inTouchMode);
+    public boolean setInTouchMode(boolean inTouchMode, int pid, int uid, boolean hasPermission) {
+        return nativeSetInTouchMode(mPtr, inTouchMode, pid, uid, hasPermission);
     }
 
     @Override // Binder call
@@ -934,9 +933,7 @@
     @Override // Binder call
     public InputDevice getInputDevice(int deviceId) {
         synchronized (mInputDevicesLock) {
-            final int count = mInputDevices.length;
-            for (int i = 0; i < count; i++) {
-                final InputDevice inputDevice = mInputDevices[i];
+            for (final InputDevice inputDevice : mInputDevices) {
                 if (inputDevice.getId() == deviceId) {
                     return inputDevice;
                 }
@@ -1119,23 +1116,19 @@
             return null;
         }
         final List<KeyboardLayout> layouts = new ArrayList<>();
-        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
-            @Override
-            public void visitKeyboardLayout(Resources resources,
-                    int keyboardLayoutResId, KeyboardLayout layout) {
-                // Only select a default when we know the layout is appropriate. For now, this
-                // means its a custom layout for a specific keyboard.
-                if (layout.getVendorId() != d.getVendorId()
-                        || layout.getProductId() != d.getProductId()) {
-                    return;
-                }
-                final LocaleList locales = layout.getLocales();
-                final int numLocales = locales.size();
-                for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
-                    if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
-                        layouts.add(layout);
-                        break;
-                    }
+        visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> {
+            // Only select a default when we know the layout is appropriate. For now, this
+            // means it's a custom layout for a specific keyboard.
+            if (layout.getVendorId() != d.getVendorId()
+                    || layout.getProductId() != d.getProductId()) {
+                return;
+            }
+            final LocaleList locales = layout.getLocales();
+            final int numLocales = locales.size();
+            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+                if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
+                    layouts.add(layout);
+                    break;
                 }
             }
         });
@@ -1335,13 +1328,8 @@
     private void updateKeyboardLayouts() {
         // Scan all input devices state for keyboard layouts that have been uninstalled.
         final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
-        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
-            @Override
-            public void visitKeyboardLayout(Resources resources,
-                    int keyboardLayoutResId, KeyboardLayout layout) {
-                availableKeyboardLayouts.add(layout.getDescriptor());
-            }
-        });
+        visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) ->
+                availableKeyboardLayouts.add(layout.getDescriptor()));
         synchronized (mDataStore) {
             try {
                 mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
@@ -1368,14 +1356,8 @@
 
     @Override // Binder call
     public KeyboardLayout[] getKeyboardLayouts() {
-        final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
-        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
-            @Override
-            public void visitKeyboardLayout(Resources resources,
-                    int keyboardLayoutResId, KeyboardLayout layout) {
-                list.add(layout);
-            }
-        });
+        final ArrayList<KeyboardLayout> list = new ArrayList<>();
+        visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> list.add(layout));
         return list.toArray(new KeyboardLayout[list.size()]);
     }
 
@@ -1383,10 +1365,10 @@
     public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
             final InputDeviceIdentifier identifier) {
         final String[] enabledLayoutDescriptors =
-            getEnabledKeyboardLayoutsForInputDevice(identifier);
+                getEnabledKeyboardLayoutsForInputDevice(identifier);
         final ArrayList<KeyboardLayout> enabledLayouts =
-            new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length);
-        final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>();
+                new ArrayList<>(enabledLayoutDescriptors.length);
+        final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<>();
         visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
             boolean mHasSeenDeviceSpecificLayout;
 
@@ -1434,13 +1416,8 @@
                 "keyboardLayoutDescriptor must not be null");
 
         final KeyboardLayout[] result = new KeyboardLayout[1];
-        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
-            @Override
-            public void visitKeyboardLayout(Resources resources,
-                    int keyboardLayoutResId, KeyboardLayout layout) {
-                result[0] = layout;
-            }
-        });
+        visitKeyboardLayout(keyboardLayoutDescriptor,
+                (resources, keyboardLayoutResId, layout) -> result[0] = layout);
         if (result[0] == null) {
             Slog.w(TAG, "Could not get keyboard layout with descriptor '"
                     + keyboardLayoutDescriptor + "'.");
@@ -1472,7 +1449,7 @@
                                 | PackageManager.MATCH_DIRECT_BOOT_AWARE
                                 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
                 visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
-            } catch (NameNotFoundException ex) {
+            } catch (NameNotFoundException ignored) {
             }
         }
     }
@@ -1502,11 +1479,10 @@
 
         try {
             Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
-            XmlResourceParser parser = resources.getXml(configResId);
-            try {
+            try (XmlResourceParser parser = resources.getXml(configResId)) {
                 XmlUtils.beginDocument(parser, "keyboard-layouts");
 
-                for (;;) {
+                while (true) {
                     XmlUtils.nextElement(parser);
                     String element = parser.getName();
                     if (element == null) {
@@ -1514,22 +1490,22 @@
                     }
                     if (element.equals("keyboard-layout")) {
                         TypedArray a = resources.obtainAttributes(
-                                parser, com.android.internal.R.styleable.KeyboardLayout);
+                                parser, R.styleable.KeyboardLayout);
                         try {
                             String name = a.getString(
-                                    com.android.internal.R.styleable.KeyboardLayout_name);
+                                    R.styleable.KeyboardLayout_name);
                             String label = a.getString(
-                                    com.android.internal.R.styleable.KeyboardLayout_label);
+                                    R.styleable.KeyboardLayout_label);
                             int keyboardLayoutResId = a.getResourceId(
-                                    com.android.internal.R.styleable.KeyboardLayout_keyboardLayout,
+                                    R.styleable.KeyboardLayout_keyboardLayout,
                                     0);
                             String languageTags = a.getString(
-                                    com.android.internal.R.styleable.KeyboardLayout_locale);
+                                    R.styleable.KeyboardLayout_locale);
                             LocaleList locales = getLocalesFromLanguageTags(languageTags);
                             int vid = a.getInt(
-                                    com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
+                                    R.styleable.KeyboardLayout_vendorId, -1);
                             int pid = a.getInt(
-                                    com.android.internal.R.styleable.KeyboardLayout_productId, -1);
+                                    R.styleable.KeyboardLayout_productId, -1);
 
                             if (name == null || label == null || keyboardLayoutResId == 0) {
                                 Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
@@ -1556,8 +1532,6 @@
                                 + receiver.packageName + "/" + receiver.name);
                     }
                 }
-            } finally {
-                parser.close();
             }
         } catch (Exception ex) {
             Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
@@ -1584,10 +1558,7 @@
         if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
             return identifier.getDescriptor();
         }
-        StringBuilder bob = new StringBuilder();
-        bob.append("vendor:").append(identifier.getVendorId());
-        bob.append(",product:").append(identifier.getProductId());
-        return bob.toString();
+        return "vendor:" + identifier.getVendorId() + ",product:" + identifier.getProductId();
     }
 
     @Override // Binder call
@@ -1595,7 +1566,7 @@
 
         String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
-            String layout = null;
+            String layout;
             // try loading it using the layout descriptor if we have it
             layout = mDataStore.getCurrentKeyboardLayout(key);
             if (layout == null && !key.equals(identifier.getDescriptor())) {
@@ -1850,10 +1821,60 @@
         nativeSetPointerSpeed(mPtr, speed);
     }
 
-    private void setPointerAcceleration(float acceleration) {
+    private void setPointerAcceleration(float acceleration, int displayId) {
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            AdditionalDisplayInputProperties properties =
+                    mAdditionalDisplayInputProperties.get(displayId);
+            if (properties == null) {
+                properties = new AdditionalDisplayInputProperties();
+                mAdditionalDisplayInputProperties.put(displayId, properties);
+            }
+            properties.pointerAcceleration = acceleration;
+            if (properties.allDefaults()) {
+                mAdditionalDisplayInputProperties.remove(displayId);
+            }
+            if (mOverriddenPointerDisplayId == displayId) {
+                updatePointerAccelerationLocked(acceleration);
+            }
+        }
+    }
+
+    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
+    private void updatePointerAccelerationLocked(float acceleration) {
         nativeSetPointerAcceleration(mPtr, acceleration);
     }
 
+    private void setPointerIconVisible(boolean visible, int displayId) {
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            AdditionalDisplayInputProperties properties =
+                    mAdditionalDisplayInputProperties.get(displayId);
+            if (properties == null) {
+                properties = new AdditionalDisplayInputProperties();
+                mAdditionalDisplayInputProperties.put(displayId, properties);
+            }
+            properties.pointerIconVisible = visible;
+            if (properties.allDefaults()) {
+                mAdditionalDisplayInputProperties.remove(displayId);
+            }
+            if (mOverriddenPointerDisplayId == displayId) {
+                updatePointerIconVisibleLocked(visible);
+            }
+        }
+    }
+
+    @GuardedBy("mAdditionalDisplayInputPropertiesLock")
+    private void updatePointerIconVisibleLocked(boolean visible) {
+        if (visible) {
+            if (mIconType == PointerIcon.TYPE_CUSTOM) {
+                nativeSetCustomPointerIcon(mPtr, mIcon);
+            } else {
+                nativeSetPointerIconType(mPtr, mIconType);
+            }
+        } else {
+            nativeSetPointerIconType(mPtr, PointerIcon.TYPE_NULL);
+        }
+    }
+
     private void registerPointerSpeedSettingObserver() {
         mContext.getContentResolver().registerContentObserver(
                 Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
@@ -1870,7 +1891,7 @@
         try {
             speed = Settings.System.getIntForUser(mContext.getContentResolver(),
                     Settings.System.POINTER_SPEED, UserHandle.USER_CURRENT);
-        } catch (SettingNotFoundException snfe) {
+        } catch (SettingNotFoundException ignored) {
         }
         return speed;
     }
@@ -1988,13 +2009,27 @@
     }
 
     private void setVirtualMousePointerDisplayId(int displayId) {
-        synchronized (mPointerDisplayIdLock) {
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
             mOverriddenPointerDisplayId = displayId;
+            if (displayId != Display.INVALID_DISPLAY) {
+                final AdditionalDisplayInputProperties properties =
+                        mAdditionalDisplayInputProperties.get(displayId);
+                if (properties != null) {
+                    updatePointerAccelerationLocked(properties.pointerAcceleration);
+                    updatePointerIconVisibleLocked(properties.pointerIconVisible);
+                }
+            }
         }
         // TODO(b/215597605): trigger MousePositionTracker update
         nativeNotifyPointerDisplayIdChanged(mPtr);
     }
 
+    private int getVirtualMousePointerDisplayId() {
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            return mOverriddenPointerDisplayId;
+        }
+    }
+
     private void setDisplayEligibilityForPointerCapture(int displayId, boolean isEligible) {
         nativeSetDisplayEligibilityForPointerCapture(mPtr, displayId, isEligible);
     }
@@ -2134,7 +2169,7 @@
                 SparseArray<VibrationEffect> effects = stereo.getEffects();
                 long[] pattern = new long[0];
                 int repeat = Integer.MIN_VALUE;
-                SparseArray<int[]> amplitudes = new SparseArray<int[]>(effects.size());
+                SparseArray<int[]> amplitudes = new SparseArray<>(effects.size());
                 for (int i = 0; i < effects.size(); i++) {
                     VibrationInfo info = new VibrationInfo(effects.valueAt(i));
                     // Pattern of all effects should be same
@@ -2184,6 +2219,7 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private void notifyVibratorState(int deviceId, boolean isOn) {
         if (DEBUG) {
             Slog.d(TAG, "notifyVibratorState: deviceId=" + deviceId + " isOn=" + isOn);
@@ -2225,7 +2261,7 @@
 
     @Override // Binder call
     public boolean registerVibratorStateListener(int deviceId, IVibratorStateListener listener) {
-        Preconditions.checkNotNull(listener, "listener must not be null");
+        Objects.requireNonNull(listener, "listener must not be null");
 
         RemoteCallbackList<IVibratorStateListener> listeners;
         synchronized (mVibratorLock) {
@@ -2283,15 +2319,44 @@
 
     // Binder call
     @Override
-    public void setPointerIconType(int iconId) {
-        nativeSetPointerIconType(mPtr, iconId);
+    public void setPointerIconType(int iconType) {
+        if (iconType == PointerIcon.TYPE_CUSTOM) {
+            throw new IllegalArgumentException("Use setCustomPointerIcon to set custom pointers");
+        }
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            mIcon = null;
+            mIconType = iconType;
+            if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
+                final AdditionalDisplayInputProperties properties =
+                        mAdditionalDisplayInputProperties.get(mOverriddenPointerDisplayId);
+                if (properties == null || properties.pointerIconVisible) {
+                    nativeSetPointerIconType(mPtr, mIconType);
+                }
+            } else {
+                nativeSetPointerIconType(mPtr, mIconType);
+            }
+        }
     }
 
     // Binder call
     @Override
     public void setCustomPointerIcon(PointerIcon icon) {
         Objects.requireNonNull(icon);
-        nativeSetCustomPointerIcon(mPtr, icon);
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            mIconType = PointerIcon.TYPE_CUSTOM;
+            mIcon = icon;
+            if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
+                final AdditionalDisplayInputProperties properties =
+                        mAdditionalDisplayInputProperties.get(mOverriddenPointerDisplayId);
+                if (properties == null || properties.pointerIconVisible) {
+                    // Only set the icon if it is not currently hidden; otherwise, it will be set
+                    // once it's no longer hidden.
+                    nativeSetCustomPointerIcon(mPtr, mIcon);
+                }
+            } else {
+                nativeSetCustomPointerIcon(mPtr, mIcon);
+            }
+        }
     }
 
     /**
@@ -2383,7 +2448,7 @@
         }
         Objects.requireNonNull(listener, "listener must not be null");
 
-        synchronized (mInputDevicesLock) {
+        synchronized (mSensorEventLock) {
             int callingPid = Binder.getCallingPid();
             if (mSensorEventListeners.get(callingPid) != null) {
                 Slog.e(TAG, "The calling process " + callingPid + " has already "
@@ -2415,7 +2480,7 @@
 
         Objects.requireNonNull(listener, "listener must not be null");
 
-        synchronized (mInputDevicesLock) {
+        synchronized (mSensorEventLock) {
             int callingPid = Binder.getCallingPid();
             if (mSensorEventListeners.get(callingPid) != null) {
                 SensorEventListenerRecord record = mSensorEventListeners.get(callingPid);
@@ -2429,7 +2494,7 @@
 
     @Override // Binder call
     public boolean flushSensor(int deviceId, int sensorType) {
-        synchronized (mInputDevicesLock) {
+        synchronized (mSensorEventLock) {
             int callingPid = Binder.getCallingPid();
             SensorEventListenerRecord listener = mSensorEventListeners.get(callingPid);
             if (listener != null) {
@@ -2497,7 +2562,7 @@
      * Set specified light state with for a specific input device.
      */
     private void setLightStateInternal(int deviceId, Light light, LightState lightState) {
-        Preconditions.checkNotNull(light, "light does not exist");
+        Objects.requireNonNull(light, "light does not exist");
         if (DEBUG) {
             Slog.d(TAG, "setLightStateInternal device " + deviceId + " light " + light
                     + "lightState " + lightState);
@@ -2560,7 +2625,7 @@
 
     @Override
     public void openLightSession(int deviceId, String opPkg, IBinder token) {
-        Preconditions.checkNotNull(token);
+        Objects.requireNonNull(token);
         synchronized (mLightLock) {
             Preconditions.checkState(mLightSessions.get(token) == null, "already registered");
             LightSession lightSession = new LightSession(deviceId, opPkg, token);
@@ -2579,7 +2644,7 @@
 
     @Override
     public void closeLightSession(int deviceId, IBinder token) {
-        Preconditions.checkNotNull(token);
+        Objects.requireNonNull(token);
         synchronized (mLightLock) {
             LightSession lightSession = mLightSessions.get(token);
             Preconditions.checkState(lightSession != null, "not registered");
@@ -2620,6 +2685,7 @@
         pw.println("Input Manager Service (Java) State:");
         dumpAssociations(pw, "  " /*prefix*/);
         dumpSpyWindowGestureMonitors(pw, "  " /*prefix*/);
+        dumpDisplayInputPropertiesValues(pw, "  " /* prefix */);
     }
 
     private void dumpAssociations(PrintWriter pw, String prefix) {
@@ -2660,6 +2726,25 @@
         }
     }
 
+    private void dumpDisplayInputPropertiesValues(PrintWriter pw, String prefix) {
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
+            if (mAdditionalDisplayInputProperties.size() != 0) {
+                pw.println(prefix + "mAdditionalDisplayInputProperties:");
+                for (int i = 0; i < mAdditionalDisplayInputProperties.size(); i++) {
+                    pw.println(prefix + "  displayId: "
+                            + mAdditionalDisplayInputProperties.keyAt(i));
+                    final AdditionalDisplayInputProperties properties =
+                            mAdditionalDisplayInputProperties.valueAt(i);
+                    pw.println(prefix + "  pointerAcceleration: " + properties.pointerAcceleration);
+                    pw.println(prefix + "  pointerIconVisible: " + properties.pointerIconVisible);
+                }
+            }
+            if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
+                pw.println(prefix + "mOverriddenPointerDisplayId: " + mOverriddenPointerDisplayId);
+            }
+        }
+    }
+
     private boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == Process.myPid()) {
@@ -2683,17 +2768,19 @@
         synchronized (mInputFilterLock) { }
         synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
         synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
-        synchronized (mPointerDisplayIdLock) { /* Test if blocked by pointer display id lock */ }
         synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ }
+        synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ }
         nativeMonitor(mPtr);
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private void notifyConfigurationChanged(long whenNanos) {
         mWindowManagerCallbacks.notifyConfigurationChanged();
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private void notifyInputDevicesChanged(InputDevice[] inputDevices) {
         synchronized (mInputDevicesLock) {
             if (!mInputDevicesChangedPending) {
@@ -2707,6 +2794,7 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private void notifySwitch(long whenNanos, int switchValues, int switchMask) {
         if (DEBUG) {
             Slog.d(TAG, "notifySwitch: values=" + Integer.toHexString(switchValues)
@@ -2739,7 +2827,7 @@
             SomeArgs args = SomeArgs.obtain();
             args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
             args.argi2 = (int) (whenNanos >> 32);
-            args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
+            args.arg1 = (switchValues & SW_TABLET_MODE_BIT) != 0;
             mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
                     args).sendToTarget();
         }
@@ -2752,6 +2840,7 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private void notifyInputChannelBroken(IBinder token) {
         synchronized (mInputMonitors) {
             if (mInputMonitors.containsKey(token)) {
@@ -2762,16 +2851,19 @@
     }
 
     // Native callback
+    @SuppressWarnings("unused")
     private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
         mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken);
     }
 
     // Native callback
+    @SuppressWarnings("unused")
     private void notifyDropWindow(IBinder token, float x, float y) {
         mWindowManagerCallbacks.notifyDropWindow(token, x, y);
     }
 
     // Native callback
+    @SuppressWarnings("unused")
     private void notifyUntrustedTouch(String packageName) {
         // TODO(b/169067926): Remove toast after gathering feedback on dogfood.
         if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains(
@@ -2787,11 +2879,13 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private void notifyNoFocusedWindowAnr(InputApplicationHandle inputApplicationHandle) {
         mWindowManagerCallbacks.notifyNoFocusedWindowAnr(inputApplicationHandle);
     }
 
     // Native callback
+    @SuppressWarnings("unused")
     private void notifyWindowUnresponsive(IBinder token, String reason) {
         int gestureMonitorPid = -1;
         synchronized (mInputMonitors) {
@@ -2808,11 +2902,13 @@
     }
 
     // Native callback
+    @SuppressWarnings("unused")
     private void notifyMonitorUnresponsive(int pid, String reason) {
         mWindowManagerCallbacks.notifyGestureMonitorUnresponsive(pid, reason);
     }
 
     // Native callback
+    @SuppressWarnings("unused")
     private void notifyWindowResponsive(IBinder token) {
         int gestureMonitorPid = -1;
         synchronized (mInputMonitors) {
@@ -2829,11 +2925,13 @@
     }
 
     // Native callback
+    @SuppressWarnings("unused")
     private void notifyMonitorResponsive(int pid) {
         mWindowManagerCallbacks.notifyGestureMonitorResponsive(pid);
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp,
             float[] values) {
         if (DEBUG) {
@@ -2857,6 +2955,7 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) {
         mSensorAccuracyListenersToNotify.clear();
         final int numListeners;
@@ -2874,6 +2973,7 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     final boolean filterInputEvent(InputEvent event, int policyFlags) {
         synchronized (mInputFilterLock) {
             if (mInputFilter != null) {
@@ -2890,11 +2990,13 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
         return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int interceptMotionBeforeQueueingNonInteractive(int displayId,
             long whenNanos, int policyFlags) {
         return mWindowManagerCallbacks.interceptMotionBeforeQueueingNonInteractive(
@@ -2902,33 +3004,39 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) {
         return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) {
         return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags);
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private boolean checkInjectEventsPermission(int injectorPid, int injectorUid) {
         return mContext.checkPermission(android.Manifest.permission.INJECT_EVENTS,
                 injectorPid, injectorUid) == PackageManager.PERMISSION_GRANTED;
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private void onPointerDownOutsideFocus(IBinder touchedToken) {
         mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken);
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int getVirtualKeyQuietTimeMillis() {
         return mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_virtualKeyQuietTimeMillis);
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private static String[] getExcludedDeviceNames() {
         List<String> names = new ArrayList<>();
         // Read partner-provided list of excluded input devices
@@ -2984,6 +3092,7 @@
     }
 
     // Native callback
+    @SuppressWarnings("unused")
     private String[] getInputPortAssociations() {
         final Map<String, Integer> associations = new HashMap<>(mStaticAssociations);
 
@@ -2996,6 +3105,7 @@
     }
 
     // Native callback
+    @SuppressWarnings("unused")
     private String[] getInputUniqueIdAssociations() {
         final Map<String, String> associations;
         synchronized (mAssociationsLock) {
@@ -3016,46 +3126,55 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int getKeyRepeatTimeout() {
         return ViewConfiguration.getKeyRepeatTimeout();
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int getKeyRepeatDelay() {
         return ViewConfiguration.getKeyRepeatDelay();
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int getHoverTapTimeout() {
         return ViewConfiguration.getHoverTapTimeout();
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int getHoverTapSlop() {
         return ViewConfiguration.getHoverTapSlop();
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int getDoubleTapTimeout() {
         return ViewConfiguration.getDoubleTapTimeout();
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int getLongPressTimeout() {
         return ViewConfiguration.getLongPressTimeout();
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int getPointerLayer() {
         return mWindowManagerCallbacks.getPointerLayer();
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private PointerIcon getPointerIcon(int displayId) {
         return PointerIcon.getDefaultIcon(getContextForPointerIcon(displayId));
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private long getParentSurfaceForPointers(int displayId) {
         final SurfaceControl sc = mWindowManagerCallbacks.getParentSurfaceForPointers(displayId);
         if (sc == null) {
@@ -3101,8 +3220,9 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private int getPointerDisplayId() {
-        synchronized (mPointerDisplayIdLock) {
+        synchronized (mAdditionalDisplayInputPropertiesLock) {
             // Prefer the override to all other displays.
             if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
                 return mOverriddenPointerDisplayId;
@@ -3112,6 +3232,7 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
         if (!mSystemReady) {
             return null;
@@ -3123,19 +3244,15 @@
         }
 
         final String[] result = new String[2];
-        visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
-            @Override
-            public void visitKeyboardLayout(Resources resources,
-                    int keyboardLayoutResId, KeyboardLayout layout) {
-                try (final InputStreamReader stream = new InputStreamReader(
-                               resources.openRawResource(keyboardLayoutResId))) {
-                    result[0] = layout.getDescriptor();
-                    result[1] = Streams.readFully(stream);
-                } catch (IOException ex) {
-                } catch (NotFoundException ex) {
-                }
-            }
-        });
+        visitKeyboardLayout(keyboardLayoutDescriptor,
+                (resources, keyboardLayoutResId, layout) -> {
+                    try (InputStreamReader stream = new InputStreamReader(
+                            resources.openRawResource(keyboardLayoutResId))) {
+                        result[0] = layout.getDescriptor();
+                        result[1] = Streams.readFully(stream);
+                    } catch (IOException | NotFoundException ignored) {
+                    }
+                });
         if (result[0] == null) {
             Slog.w(TAG, "Could not get keyboard layout with descriptor '"
                     + keyboardLayoutDescriptor + "'.");
@@ -3145,6 +3262,7 @@
     }
 
     // Native callback.
+    @SuppressWarnings("unused")
     private String getDeviceAlias(String uniqueId) {
         if (BluetoothAdapter.checkBluetoothAddress(uniqueId)) {
             // TODO(BT) mBluetoothService.getRemoteAlias(uniqueId)
@@ -3294,8 +3412,18 @@
      * Callback interface implemented by WiredAccessoryObserver.
      */
     public interface WiredAccessoryCallbacks {
-        public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
-        public void systemReady();
+        /**
+         * Notifies WiredAccessoryObserver that input state for wired accessories has changed
+         * @param whenNanos When the wired accessories changed
+         * @param switchValues The state of the switches
+         * @param switchMask The mask of switches that changed
+         */
+        void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
+
+        /**
+         * Notifies WiredAccessoryObserver that the system is now ready.
+         */
+        void systemReady();
     }
 
     /**
@@ -3326,7 +3454,7 @@
                     break;
                 case MSG_DELIVER_TABLET_MODE_CHANGED:
                     SomeArgs args = (SomeArgs) msg.obj;
-                    long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
+                    long whenNanos = (args.argi1 & 0xFFFFFFFFL) | ((long) args.argi2 << 32);
                     boolean inTabletMode = (boolean) args.arg1;
                     deliverTabletModeChanged(whenNanos, inTabletMode);
                     break;
@@ -3338,8 +3466,10 @@
      * Hosting interface for input filters to call back into the input manager.
      */
     private final class InputFilterHost extends IInputFilterHost.Stub {
+        @GuardedBy("mInputFilterLock")
         private boolean mDisconnected;
 
+        @GuardedBy("mInputFilterLock")
         public void disconnectLocked() {
             mDisconnected = true;
         }
@@ -3375,11 +3505,7 @@
 
         @Override
         public void dispose() {
-            if (USE_SPY_WINDOW_GESTURE_MONITORS) {
-                removeSpyWindowGestureMonitor(mInputChannelToken);
-                return;
-            }
-            nativeRemoveInputChannel(mPtr, mInputChannelToken);
+            removeSpyWindowGestureMonitor(mInputChannelToken);
         }
     }
 
@@ -3592,13 +3718,18 @@
         }
 
         @Override
+        public int getVirtualMousePointerDisplayId() {
+            return InputManagerService.this.getVirtualMousePointerDisplayId();
+        }
+
+        @Override
         public PointF getCursorPosition() {
             return mWindowManagerCallbacks.getCursorPosition();
         }
 
         @Override
-        public void setPointerAcceleration(float acceleration) {
-            InputManagerService.this.setPointerAcceleration(acceleration);
+        public void setPointerAcceleration(float acceleration, int displayId) {
+            InputManagerService.this.setPointerAcceleration(acceleration, displayId);
         }
 
         @Override
@@ -3607,6 +3738,11 @@
         }
 
         @Override
+        public void setPointerIconVisible(boolean visible, int displayId) {
+            InputManagerService.this.setPointerIconVisible(visible, displayId);
+        }
+
+        @Override
         public void registerLidSwitchCallback(LidSwitchCallback callbacks) {
             registerLidSwitchCallbackInternal(callbacks);
         }
@@ -3633,4 +3769,21 @@
         new InputShellCommand().exec(this, in, out, err, args, callback, resultReceiver);
     }
 
+    private static class AdditionalDisplayInputProperties {
+
+        static final boolean DEFAULT_POINTER_ICON_VISIBLE = true;
+        static final float DEFAULT_POINTER_ACCELERATION =
+                (float) IInputConstants.DEFAULT_POINTER_ACCELERATION;
+
+        // The pointer acceleration for this display.
+        public float pointerAcceleration = DEFAULT_POINTER_ACCELERATION;
+
+        // Whether the pointer icon should be visible or hidden on this display.
+        public boolean pointerIconVisible = DEFAULT_POINTER_ICON_VISIBLE;
+
+        public boolean allDefaults() {
+            return Float.compare(pointerAcceleration, DEFAULT_POINTER_ACCELERATION) == 0
+                    && pointerIconVisible == DEFAULT_POINTER_ICON_VISIBLE;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c207738a..ba15a04 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1495,8 +1495,7 @@
 
         @Override
         public void onStart() {
-            LocalServices.addService(InputMethodManagerInternal.class,
-                    new LocalServiceImpl(mService));
+            mService.publishLocalService();
             publishBinderService(Context.INPUT_METHOD_SERVICE, mService, false /*allowIsolated*/,
                     DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
         }
@@ -4866,26 +4865,6 @@
         return mCurrentSubtype;
     }
 
-    private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
-        synchronized (ImfLock.class) {
-            return getInputMethodListLocked(userId, DirectBootAwareness.AUTO);
-        }
-    }
-
-    private List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
-        synchronized (ImfLock.class) {
-            return getEnabledInputMethodListLocked(userId);
-        }
-    }
-
-    private void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
-            InlineSuggestionsRequestInfo requestInfo,
-            IInlineSuggestionsRequestCallback callback) {
-        synchronized (ImfLock.class) {
-            onCreateInlineSuggestionsRequestLocked(userId, requestInfo, callback);
-        }
-    }
-
     private ArrayMap<String, InputMethodInfo> queryMethodMapForUser(@UserIdInt int userId) {
         final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
         final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
@@ -4897,161 +4876,153 @@
         return methodMap;
     }
 
-    private boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
-        synchronized (ImfLock.class) {
-            if (userId == mSettings.getCurrentUserId()) {
-                if (!mMethodMap.containsKey(imeId)
-                        || !mSettings.getEnabledInputMethodListLocked()
-                                .contains(mMethodMap.get(imeId))) {
-                    return false; // IME is not found or not enabled.
-                }
-                setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
-                return true;
-            }
-            final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId);
-            final InputMethodSettings settings = new InputMethodSettings(
-                    mContext.getResources(), mContext.getContentResolver(), methodMap,
-                    userId, false);
-            if (!methodMap.containsKey(imeId)
-                    || !settings.getEnabledInputMethodListLocked()
-                            .contains(methodMap.get(imeId))) {
+    @GuardedBy("ImfLock.class")
+    private boolean switchToInputMethodLocked(String imeId, @UserIdInt int userId) {
+        if (userId == mSettings.getCurrentUserId()) {
+            if (!mMethodMap.containsKey(imeId)
+                    || !mSettings.getEnabledInputMethodListLocked()
+                            .contains(mMethodMap.get(imeId))) {
                 return false; // IME is not found or not enabled.
             }
-            settings.putSelectedInputMethod(imeId);
-            settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
+            setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
             return true;
         }
+        final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId);
+        final InputMethodSettings settings = new InputMethodSettings(
+                mContext.getResources(), mContext.getContentResolver(), methodMap,
+                userId, false);
+        if (!methodMap.containsKey(imeId)
+                || !settings.getEnabledInputMethodListLocked()
+                        .contains(methodMap.get(imeId))) {
+            return false; // IME is not found or not enabled.
+        }
+        settings.putSelectedInputMethod(imeId);
+        settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
+        return true;
     }
 
-    private boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId) {
-        synchronized (ImfLock.class) {
-            if (userId == mSettings.getCurrentUserId()) {
-                if (!mMethodMap.containsKey(imeId)) {
-                    return false; // IME is not found.
-                }
-                setInputMethodEnabledLocked(imeId, enabled);
-                return true;
-            }
-            final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId);
-            final InputMethodSettings settings = new InputMethodSettings(
-                    mContext.getResources(), mContext.getContentResolver(), methodMap,
-                    userId, false);
-            if (!methodMap.containsKey(imeId)) {
-                return false; // IME is not found.
-            }
-            if (enabled) {
-                if (!settings.getEnabledInputMethodListLocked().contains(methodMap.get(imeId))) {
-                    settings.appendAndPutEnabledInputMethodLocked(imeId, false);
-                }
-            } else {
-                settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
-                        new StringBuilder(),
-                        settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId);
-            }
-            return true;
-        }
+    private void publishLocalService() {
+        LocalServices.addService(InputMethodManagerInternal.class, new LocalServiceImpl());
     }
 
-    private boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
-            int displayId) {
-        //TODO(b/150843766): Check if Input Token is valid.
-        final IBinder curHostInputToken;
-        synchronized (ImfLock.class) {
-            if (displayId != mCurTokenDisplayId || mCurHostInputToken == null) {
-                return false;
-            }
-            curHostInputToken = mCurHostInputToken;
-        }
-        return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
-    }
-
-    private void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
-        synchronized (ImfLock.class) {
-            if (mCurFocusedWindow != windowToken) {
-                // mCurPerceptible was set by the focused window, but it is no longer in control,
-                // so we reset mCurPerceptible.
-                mCurPerceptible = true;
-            }
-            if (imeParentChanged) {
-                // Hide the IME method menu earlier when the IME surface parent will change in
-                // case seeing the dialog dismiss flickering during the next focused window
-                // starting the input connection.
-                mMenuController.hideInputMethodMenu();
-            }
-        }
-    }
-
-    private static final class LocalServiceImpl extends InputMethodManagerInternal {
-        @NonNull
-        private final InputMethodManagerService mService;
-
-        LocalServiceImpl(@NonNull InputMethodManagerService service) {
-            mService = service;
-        }
+    private final class LocalServiceImpl extends InputMethodManagerInternal {
 
         @Override
         public void setInteractive(boolean interactive) {
             // Do everything in handler so as not to block the caller.
-            mService.mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0)
-                    .sendToTarget();
+            mHandler.obtainMessage(MSG_SET_INTERACTIVE, interactive ? 1 : 0, 0).sendToTarget();
         }
 
         @Override
         public void hideCurrentInputMethod(@SoftInputShowHideReason int reason) {
-            mService.mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
-            mService.mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget();
+            mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
+            mHandler.obtainMessage(MSG_HIDE_CURRENT_INPUT_METHOD, reason).sendToTarget();
         }
 
         @Override
         public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
-            return mService.getInputMethodListAsUser(userId);
+            synchronized (ImfLock.class) {
+                return getInputMethodListLocked(userId, DirectBootAwareness.AUTO);
+            }
         }
 
         @Override
         public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
-            return mService.getEnabledInputMethodListAsUser(userId);
+            synchronized (ImfLock.class) {
+                return getEnabledInputMethodListLocked(userId);
+            }
         }
 
         @Override
         public void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
                 InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) {
-            mService.onCreateInlineSuggestionsRequest(userId, requestInfo, cb);
+            synchronized (ImfLock.class) {
+                onCreateInlineSuggestionsRequestLocked(userId, requestInfo, cb);
+            }
         }
 
         @Override
         public boolean switchToInputMethod(String imeId, @UserIdInt int userId) {
-            return mService.switchToInputMethod(imeId, userId);
+            synchronized (ImfLock.class) {
+                return switchToInputMethodLocked(imeId, userId);
+            }
         }
 
         @Override
         public boolean setInputMethodEnabled(String imeId, boolean enabled, @UserIdInt int userId) {
-            return mService.setInputMethodEnabled(imeId, enabled, userId);
+            synchronized (ImfLock.class) {
+                if (userId == mSettings.getCurrentUserId()) {
+                    if (!mMethodMap.containsKey(imeId)) {
+                        return false; // IME is not found.
+                    }
+                    setInputMethodEnabledLocked(imeId, enabled);
+                    return true;
+                }
+                final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId);
+                final InputMethodSettings settings = new InputMethodSettings(
+                        mContext.getResources(), mContext.getContentResolver(), methodMap,
+                        userId, false);
+                if (!methodMap.containsKey(imeId)) {
+                    return false; // IME is not found.
+                }
+                if (enabled) {
+                    if (!settings.getEnabledInputMethodListLocked().contains(
+                            methodMap.get(imeId))) {
+                        settings.appendAndPutEnabledInputMethodLocked(imeId, false);
+                    }
+                } else {
+                    settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
+                            new StringBuilder(),
+                            settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId);
+                }
+                return true;
+            }
         }
 
         @Override
         public void registerInputMethodListListener(InputMethodListListener listener) {
-            mService.mInputMethodListListeners.addIfAbsent(listener);
+            mInputMethodListListeners.addIfAbsent(listener);
         }
 
         @Override
         public boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
                 int displayId) {
-            return mService.transferTouchFocusToImeWindow(sourceInputToken, displayId);
+            //TODO(b/150843766): Check if Input Token is valid.
+            final IBinder curHostInputToken;
+            synchronized (ImfLock.class) {
+                if (displayId != mCurTokenDisplayId || mCurHostInputToken == null) {
+                    return false;
+                }
+                curHostInputToken = mCurHostInputToken;
+            }
+            return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
         }
 
         @Override
         public void reportImeControl(@Nullable IBinder windowToken, boolean imeParentChanged) {
-            mService.reportImeControl(windowToken, imeParentChanged);
+            synchronized (ImfLock.class) {
+                if (mCurFocusedWindow != windowToken) {
+                    // mCurPerceptible was set by the focused window, but it is no longer in
+                    // control, so we reset mCurPerceptible.
+                    mCurPerceptible = true;
+                }
+                if (imeParentChanged) {
+                    // Hide the IME method menu earlier when the IME surface parent will change in
+                    // case seeing the dialog dismiss flickering during the next focused window
+                    // starting the input connection.
+                    mMenuController.hideInputMethodMenu();
+                }
+            }
         }
 
         @Override
         public void removeImeSurface() {
-            mService.mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget();
+            mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE).sendToTarget();
         }
 
         @Override
         public void updateImeWindowStatus(boolean disableImeIcon) {
-            mService.mHandler.obtainMessage(MSG_UPDATE_IME_WINDOW_STATUS, disableImeIcon ? 1 : 0, 0)
+            mHandler.obtainMessage(MSG_UPDATE_IME_WINDOW_STATUS, disableImeIcon ? 1 : 0, 0)
                     .sendToTarget();
         }
     }
@@ -5689,7 +5660,7 @@
                 if (!userHasDebugPriv(userId, shellCommand)) {
                     continue;
                 }
-                boolean failedToSelectUnknownIme = !switchToInputMethod(imeId, userId);
+                boolean failedToSelectUnknownIme = !switchToInputMethodLocked(imeId, userId);
                 if (failedToSelectUnknownIme) {
                     error.print("Unknown input method ");
                     error.print(imeId);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 8ce67a6..76d06c8 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -119,9 +119,7 @@
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
 import static com.android.internal.util.XmlUtils.readStringAttribute;
-import static com.android.internal.util.XmlUtils.readThisIntArrayXml;
 import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
-import static com.android.internal.util.XmlUtils.writeIntArrayXml;
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
@@ -246,7 +244,6 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.StatLogger;
-import com.android.internal.util.XmlUtils;
 import com.android.net.module.util.NetworkIdentityUtils;
 import com.android.net.module.util.NetworkStatsUtils;
 import com.android.net.module.util.PermissionUtils;
@@ -260,8 +257,6 @@
 
 import libcore.io.IoUtils;
 
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -336,7 +331,8 @@
     private static final int VERSION_ADDED_CYCLE = 11;
     private static final int VERSION_ADDED_NETWORK_TYPES = 12;
     private static final int VERSION_SUPPORTED_CARRIER_USAGE = 13;
-    private static final int VERSION_LATEST = VERSION_SUPPORTED_CARRIER_USAGE;
+    private static final int VERSION_REMOVED_SUBSCRIPTION_PLANS = 14;
+    private static final int VERSION_LATEST = VERSION_REMOVED_SUBSCRIPTION_PLANS;
 
     @VisibleForTesting
     public static final int TYPE_WARNING = SystemMessage.NOTE_NET_WARNING;
@@ -349,7 +345,6 @@
 
     private static final String TAG_POLICY_LIST = "policy-list";
     private static final String TAG_NETWORK_POLICY = "network-policy";
-    private static final String TAG_SUBSCRIPTION_PLAN = "subscription-plan";
     private static final String TAG_UID_POLICY = "uid-policy";
     private static final String TAG_APP_POLICY = "app-policy";
     private static final String TAG_WHITELIST = "whitelist";
@@ -426,6 +421,13 @@
      * obj = oldBlockedReasons
      */
     private static final int MSG_BLOCKED_REASON_CHANGED = 21;
+    /**
+     * Message to indicate that subscription plans expired and should be cleared.
+     * arg1 = subId
+     * arg2 = setSubscriptionPlans call ID
+     * obj = callingPackage
+     */
+    private static final int MSG_CLEAR_SUBSCRIPTION_PLANS = 22;
 
     private static final int UID_MSG_STATE_CHANGED = 100;
     private static final int UID_MSG_GONE = 101;
@@ -492,6 +494,12 @@
     /** Map from subId to package name that owns subscription plans. */
     @GuardedBy("mNetworkPoliciesSecondLock")
     final SparseArray<String> mSubscriptionPlansOwner = new SparseArray<>();
+    /** Map from subId to the ID of the clear plans request. */
+    @GuardedBy("mNetworkPoliciesSecondLock")
+    final SparseIntArray mSetSubscriptionPlansIds = new SparseIntArray();
+    /** Atomic integer to generate a new ID for each clear plans request. */
+    @GuardedBy("mNetworkPoliciesSecondLock")
+    int mSetSubscriptionPlansIdCounter = 0;
 
     /** Map from subId to daily opportunistic quota. */
     @GuardedBy("mNetworkPoliciesSecondLock")
@@ -2523,56 +2531,6 @@
                                     warningBytes, limitBytes, lastWarningSnooze,
                                     lastLimitSnooze, metered, inferred));
                         }
-
-                    } else if (TAG_SUBSCRIPTION_PLAN.equals(tag)) {
-                        final String start = readStringAttribute(in, ATTR_CYCLE_START);
-                        final String end = readStringAttribute(in, ATTR_CYCLE_END);
-                        final String period = readStringAttribute(in, ATTR_CYCLE_PERIOD);
-                        final SubscriptionPlan.Builder builder = new SubscriptionPlan.Builder(
-                                RecurrenceRule.convertZonedDateTime(start),
-                                RecurrenceRule.convertZonedDateTime(end),
-                                RecurrenceRule.convertPeriod(period));
-                        builder.setTitle(readStringAttribute(in, ATTR_TITLE));
-                        builder.setSummary(readStringAttribute(in, ATTR_SUMMARY));
-
-                        final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES,
-                                SubscriptionPlan.BYTES_UNKNOWN);
-                        final int limitBehavior = readIntAttribute(in, ATTR_LIMIT_BEHAVIOR,
-                                SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN);
-                        if (limitBytes != SubscriptionPlan.BYTES_UNKNOWN
-                                && limitBehavior != SubscriptionPlan.LIMIT_BEHAVIOR_UNKNOWN) {
-                            builder.setDataLimit(limitBytes, limitBehavior);
-                        }
-
-                        final long usageBytes = readLongAttribute(in, ATTR_USAGE_BYTES,
-                                SubscriptionPlan.BYTES_UNKNOWN);
-                        final long usageTime = readLongAttribute(in, ATTR_USAGE_TIME,
-                                SubscriptionPlan.TIME_UNKNOWN);
-                        if (usageBytes != SubscriptionPlan.BYTES_UNKNOWN
-                                && usageTime != SubscriptionPlan.TIME_UNKNOWN) {
-                            builder.setDataUsage(usageBytes, usageTime);
-                        }
-
-                        final int subId = readIntAttribute(in, ATTR_SUB_ID);
-                        final String ownerPackage = readStringAttribute(in, ATTR_OWNER_PACKAGE);
-
-                        if (version >= VERSION_ADDED_NETWORK_TYPES) {
-                            final int depth = in.getDepth();
-                            while (XmlUtils.nextElementWithin(in, depth)) {
-                                if (TAG_XML_UTILS_INT_ARRAY.equals(in.getName())
-                                        && ATTR_NETWORK_TYPES.equals(
-                                                readStringAttribute(in, ATTR_XML_UTILS_NAME))) {
-                                    final int[] networkTypes =
-                                            readThisIntArrayXml(in, TAG_XML_UTILS_INT_ARRAY, null);
-                                    builder.setNetworkTypes(networkTypes);
-                                }
-                            }
-                        }
-
-                        final SubscriptionPlan plan = builder.build();
-                        mSubscriptionPlans.put(subId, ArrayUtils.appendElement(
-                                SubscriptionPlan.class, mSubscriptionPlans.get(subId), plan));
-                        mSubscriptionPlansOwner.put(subId, ownerPackage);
                     } else if (TAG_UID_POLICY.equals(tag)) {
                         final int uid = readIntAttribute(in, ATTR_UID);
                         final int policy = readIntAttribute(in, ATTR_POLICY);
@@ -2763,38 +2721,6 @@
                 out.endTag(null, TAG_NETWORK_POLICY);
             }
 
-            // write all known subscription plans
-            for (int i = 0; i < mSubscriptionPlans.size(); i++) {
-                final int subId = mSubscriptionPlans.keyAt(i);
-                if (subId == INVALID_SUBSCRIPTION_ID) continue;
-                final String ownerPackage = mSubscriptionPlansOwner.get(subId);
-                final SubscriptionPlan[] plans = mSubscriptionPlans.valueAt(i);
-                if (ArrayUtils.isEmpty(plans)) continue;
-
-                for (SubscriptionPlan plan : plans) {
-                    out.startTag(null, TAG_SUBSCRIPTION_PLAN);
-                    writeIntAttribute(out, ATTR_SUB_ID, subId);
-                    writeStringAttribute(out, ATTR_OWNER_PACKAGE, ownerPackage);
-                    final RecurrenceRule cycleRule = plan.getCycleRule();
-                    writeStringAttribute(out, ATTR_CYCLE_START,
-                            RecurrenceRule.convertZonedDateTime(cycleRule.start));
-                    writeStringAttribute(out, ATTR_CYCLE_END,
-                            RecurrenceRule.convertZonedDateTime(cycleRule.end));
-                    writeStringAttribute(out, ATTR_CYCLE_PERIOD,
-                            RecurrenceRule.convertPeriod(cycleRule.period));
-                    writeStringAttribute(out, ATTR_TITLE, plan.getTitle());
-                    writeStringAttribute(out, ATTR_SUMMARY, plan.getSummary());
-                    writeLongAttribute(out, ATTR_LIMIT_BYTES, plan.getDataLimitBytes());
-                    writeIntAttribute(out, ATTR_LIMIT_BEHAVIOR, plan.getDataLimitBehavior());
-                    writeLongAttribute(out, ATTR_USAGE_BYTES, plan.getDataUsageBytes());
-                    writeLongAttribute(out, ATTR_USAGE_TIME, plan.getDataUsageTime());
-                    try {
-                        writeIntArrayXml(plan.getNetworkTypes(), ATTR_NETWORK_TYPES, out);
-                    } catch (XmlPullParserException ignored) { }
-                    out.endTag(null, TAG_SUBSCRIPTION_PLAN);
-                }
-            }
-
             // write all known uid policies
             for (int i = 0; i < mUidPolicy.size(); i++) {
                 final int uid = mUidPolicy.keyAt(i);
@@ -3668,7 +3594,8 @@
     }
 
     @Override
-    public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage) {
+    public void setSubscriptionPlans(int subId, SubscriptionPlan[] plans,
+            long expirationDurationMillis, String callingPackage) {
         enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
         enforceSubscriptionPlanValidity(plans);
 
@@ -3678,34 +3605,47 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            synchronized (mUidRulesFirstLock) {
-                synchronized (mNetworkPoliciesSecondLock) {
-                    mSubscriptionPlans.put(subId, plans);
-                    mSubscriptionPlansOwner.put(subId, callingPackage);
-
-                    final String subscriberId = mSubIdToSubscriberId.get(subId, null);
-                    if (subscriberId != null) {
-                        ensureActiveCarrierPolicyAL(subId, subscriberId);
-                        maybeUpdateCarrierPolicyCycleAL(subId, subscriberId);
-                    } else {
-                        Slog.wtf(TAG, "Missing subscriberId for subId " + subId);
-                    }
-
-                    handleNetworkPoliciesUpdateAL(true);
-                }
-            }
-
-            final Intent intent = new Intent(SubscriptionManager.ACTION_SUBSCRIPTION_PLANS_CHANGED);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
-            mContext.sendBroadcast(intent, android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS);
-            mHandler.sendMessage(
-                    mHandler.obtainMessage(MSG_SUBSCRIPTION_PLANS_CHANGED, subId, 0, plans));
+            setSubscriptionPlansInternal(subId, plans, expirationDurationMillis, callingPackage);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
     }
 
+    private void setSubscriptionPlansInternal(int subId, SubscriptionPlan[] plans,
+            long expirationDurationMillis, String callingPackage) {
+        synchronized (mUidRulesFirstLock) {
+            synchronized (mNetworkPoliciesSecondLock) {
+                mSubscriptionPlans.put(subId, plans);
+                mSubscriptionPlansOwner.put(subId, callingPackage);
+
+                final String subscriberId = mSubIdToSubscriberId.get(subId, null);
+                if (subscriberId != null) {
+                    ensureActiveCarrierPolicyAL(subId, subscriberId);
+                    maybeUpdateCarrierPolicyCycleAL(subId, subscriberId);
+                } else {
+                    Slog.wtf(TAG, "Missing subscriberId for subId " + subId);
+                }
+
+                handleNetworkPoliciesUpdateAL(true);
+
+                final Intent intent = new Intent(
+                        SubscriptionManager.ACTION_SUBSCRIPTION_PLANS_CHANGED);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+                mContext.sendBroadcast(intent,
+                        android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS);
+                mHandler.sendMessage(mHandler.obtainMessage(
+                        MSG_SUBSCRIPTION_PLANS_CHANGED, subId, 0, plans));
+                final int setPlansId = mSetSubscriptionPlansIdCounter++;
+                mSetSubscriptionPlansIds.put(subId, setPlansId);
+                if (expirationDurationMillis > 0) {
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_SUBSCRIPTION_PLANS,
+                            subId, setPlansId, callingPackage), expirationDurationMillis);
+                }
+            }
+        }
+    }
+
     /**
      * Only visible for testing purposes. This doesn't give any access to
      * existing plans; it simply lets the debug package define new plans.
@@ -3728,7 +3668,7 @@
 
     @Override
     public void setSubscriptionOverride(int subId, int overrideMask, int overrideValue,
-            int[] networkTypes, long timeoutMillis, String callingPackage) {
+            int[] networkTypes, long expirationDurationMillis, String callingPackage) {
         enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
 
         final ArraySet<Integer> allNetworksSet = new ArraySet<>();
@@ -3766,10 +3706,10 @@
             args.arg3 = overrideValue;
             args.arg4 = applicableNetworks.toArray();
             mHandler.sendMessage(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args));
-            if (timeoutMillis > 0) {
+            if (expirationDurationMillis > 0) {
                 args.arg3 = 0;
                 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SUBSCRIPTION_OVERRIDE, args),
-                        timeoutMillis);
+                        expirationDurationMillis);
             }
         }
     }
@@ -5184,6 +5124,22 @@
                     mListeners.finishBroadcast();
                     return true;
                 }
+                case MSG_CLEAR_SUBSCRIPTION_PLANS: {
+                    synchronized (mUidRulesFirstLock) {
+                        synchronized (mNetworkPoliciesSecondLock) {
+                            int subId = msg.arg1;
+                            if (msg.arg2 == mSetSubscriptionPlansIds.get(subId)) {
+                                if (LOGD) Slog.d(TAG, "Clearing expired subscription plans.");
+                                setSubscriptionPlansInternal(subId, new SubscriptionPlan[]{},
+                                        0 /* expirationDurationMillis */,
+                                        (String) msg.obj /* callingPackage */);
+                            } else {
+                                if (LOGD) Slog.d(TAG, "Ignoring stale CLEAR_SUBSCRIPTION_PLANS.");
+                            }
+                        }
+                    }
+                    return true;
+                }
                 case MSG_BLOCKED_REASON_CHANGED: {
                     final int uid = msg.arg1;
                     final int newBlockedReasons = msg.arg2;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6b27321f..bc38087 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2463,7 +2463,7 @@
         };
         mAllowFgsDismissal = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED, false);
+                SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED, true);
         DeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 new HandlerExecutor(mHandler),
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 2e9ad50..2d87099 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -32,9 +32,6 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.SigningDetails;
-import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.component.ParsedApexSystemService;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.os.Binder;
@@ -59,6 +56,9 @@
 import com.android.server.pm.parsing.PackageParser2;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.component.ParsedApexSystemService;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.server.utils.TimingsTraceAndSlog;
 
 import com.google.android.collect.Lists;
@@ -414,9 +414,11 @@
             throws PackageManagerException;
 
     /**
-     * Get a map of system services defined in an apex mapped to the jar files they reside in.
+     * Get a list of apex system services implemented in an apex.
+     *
+     * <p>The list is sorted by initOrder for consistency.
      */
-    public abstract Map<String, String> getApexSystemServices();
+    public abstract List<ApexSystemServiceInfo> getApexSystemServices();
 
     /**
      * Dumps various state information to the provided {@link PrintWriter} object.
@@ -449,7 +451,7 @@
          * Map of all apex system services to the jar files they are contained in.
          */
         @GuardedBy("mLock")
-        private Map<String, String> mApexSystemServices = new ArrayMap<>();
+        private List<ApexSystemServiceInfo> mApexSystemServices = new ArrayList<>();
 
         /**
          * Contains the list of {@code packageName}s of apks-in-apex for given
@@ -605,14 +607,19 @@
                         }
 
                         String name = service.getName();
-                        if (mApexSystemServices.containsKey(name)) {
-                            throw new IllegalStateException(String.format(
-                                    "Duplicate apex-system-service %s from %s, %s",
-                                    name, mApexSystemServices.get(name), service.getJarPath()));
+                        for (ApexSystemServiceInfo info : mApexSystemServices) {
+                            if (info.getName().equals(name)) {
+                                throw new IllegalStateException(String.format(
+                                        "Duplicate apex-system-service %s from %s, %s",
+                                        name, info.mJarPath, service.getJarPath()));
+                            }
                         }
 
-                        mApexSystemServices.put(name, service.getJarPath());
+                        ApexSystemServiceInfo info = new ApexSystemServiceInfo(
+                                service.getName(), service.getJarPath(), service.getInitOrder());
+                        mApexSystemServices.add(info);
                     }
+                    Collections.sort(mApexSystemServices);
                     mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
                     if (ai.isActive) {
                         if (activePackagesSet.contains(packageInfo.packageName)) {
@@ -1133,7 +1140,7 @@
         }
 
         @Override
-        public Map<String, String> getApexSystemServices() {
+        public List<ApexSystemServiceInfo> getApexSystemServices() {
             synchronized (mLock) {
                 Preconditions.checkState(mApexSystemServices != null,
                         "APEX packages have not been scanned");
@@ -1423,10 +1430,10 @@
         }
 
         @Override
-        public Map<String, String> getApexSystemServices() {
+        public List<ApexSystemServiceInfo> getApexSystemServices() {
             // TODO(satayev): we can't really support flattened apex use case, and need to migrate
             // the manifest entries into system's manifest asap.
-            return Collections.emptyMap();
+            return Collections.emptyList();
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/ApexSystemServiceInfo.java b/services/core/java/com/android/server/pm/ApexSystemServiceInfo.java
new file mode 100644
index 0000000..f75ba6d
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ApexSystemServiceInfo.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.annotation.Nullable;
+
+/**
+ * A helper class that contains information about apex-system-service to be used within system
+ * server process.
+ */
+public final class ApexSystemServiceInfo implements Comparable<ApexSystemServiceInfo> {
+
+    final String mName;
+    @Nullable
+    final String mJarPath;
+    final int mInitOrder;
+
+    public ApexSystemServiceInfo(String name, String jarPath, int initOrder) {
+        this.mName = name;
+        this.mJarPath = jarPath;
+        this.mInitOrder = initOrder;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public String getJarPath() {
+        return mJarPath;
+    }
+
+    public int getInitOrder() {
+        return mInitOrder;
+    }
+
+    @Override
+    public int compareTo(ApexSystemServiceInfo other) {
+        if (mInitOrder == other.mInitOrder) {
+            return mName.compareTo(other.mName);
+        }
+        // higher initOrder values take precedence
+        return -Integer.compare(mInitOrder, other.mInitOrder);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index 9f086e6..d745a23 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -48,8 +48,8 @@
 import com.android.server.pm.dex.ArtManagerService;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.pkg.SELinuxUtil;
 import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.SELinuxUtil;
 
 import dalvik.system.VMRuntime;
 
@@ -549,6 +549,10 @@
     }
 
     public void migrateKeyStoreData(int previousAppId, int appId) {
+        // If previous UID is system UID, declaring inheritKeyStoreKeys is not supported.
+        // Silently ignore the request to migrate keys.
+        if (previousAppId == Process.SYSTEM_UID) return;
+
         for (int userId : mPm.resolveUserIds(UserHandle.USER_ALL)) {
             int srcUid = UserHandle.getUid(userId, previousAppId);
             int destUid = UserHandle.getUid(userId, appId);
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index d2abc69..bd32d03 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -29,10 +29,8 @@
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.SigningDetails;
 import android.content.pm.SigningInfo;
-import android.content.pm.SuspendDialogInfo;
 import android.content.pm.UserInfo;
 import android.content.pm.overlay.OverlayPaths;
-import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.service.pm.PackageProto;
 import android.util.ArrayMap;
@@ -50,7 +48,6 @@
 import com.android.server.pm.pkg.PackageState;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUnserialized;
-import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.pm.pkg.PackageUserStateImpl;
 import com.android.server.pm.pkg.PackageUserStateInternal;
 import com.android.server.pm.pkg.SuspendParams;
@@ -662,10 +659,10 @@
         usesStaticLibrariesVersions = other.usesStaticLibrariesVersions != null
                 ? Arrays.copyOf(other.usesStaticLibrariesVersions,
                 other.usesStaticLibrariesVersions.length) : null;
-
         mUserStates.clear();
         for (int i = 0; i < other.mUserStates.size(); i++) {
-            mUserStates.put(other.mUserStates.keyAt(i), other.mUserStates.valueAt(i));
+            mUserStates.put(other.mUserStates.keyAt(i),
+                    new PackageUserStateImpl(this, other.mUserStates.valueAt(i)));
         }
 
         if (mOldCodePaths != null) {
@@ -686,7 +683,7 @@
     PackageUserStateImpl modifyUserState(int userId) {
         PackageUserStateImpl state = mUserStates.get(userId);
         if (state == null) {
-            state = new PackageUserStateImpl();
+            state = new PackageUserStateImpl(this);
             mUserStates.put(userId, state);
             onChanged();
         }
@@ -696,7 +693,7 @@
     public PackageUserStateImpl getOrCreateUserState(@UserIdInt int userId) {
         PackageUserStateImpl state = mUserStates.get(userId);
         if (state == null) {
-            state = new PackageUserStateImpl();
+            state = new PackageUserStateImpl(this);
             mUserStates.put(userId, state);
         }
         return state;
@@ -1491,10 +1488,10 @@
     }
 
     @DataClass.Generated(
-            time = 1640923794772L,
+            time = 1643648635766L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
-            inputSignatures = "private  int sharedUserId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.Nullable com.android.server.pm.SharedUserSetting sharedUser\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  boolean isSharedUser()\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  int getSharedUserIdInt()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  java.lang.String getLastDisabledAppCaller(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n  boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getOverlayPathsForLibrary(int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\n  boolean getSuspended(int)\n  boolean addOrUpdateSuspension(java.lang.String,android.content.pm.SuspendDialogInfo,android.os.PersistableBundle,android.os.PersistableBundle,int)\n  boolean removeSuspension(java.lang.String,int)\n  void removeSuspension(java.util.function.Predicate<java.lang.String>,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n  android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  void setHarmfulAppWarning(int,java.lang.String)\n  java.lang.String getHarmfulAppWarning(int)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic  void setSplashScreenTheme(int,java.lang.String)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.Nullable @java.lang.Override java.lang.Integer getSharedUserId()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setSharedUser(com.android.server.pm.SharedUserSetting)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+            inputSignatures = "private  int sharedUserId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackage pkg\nprivate @android.annotation.Nullable com.android.server.pm.SharedUserSetting sharedUser\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  boolean isSharedUser()\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.parsing.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  int getSharedUserIdInt()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  android.util.ArraySet<java.lang.String> getEnabledComponents(int)\n  android.util.ArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponents(android.util.ArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(android.util.ArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackageApi getAndroidPackage()\npublic @android.annotation.Nullable @java.lang.Override int getSharedUserId()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.SharedLibraryInfo> getUsesLibraryInfos()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setSharedUser(com.android.server.pm.SharedUserSetting)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b07cd106..652080a 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2515,13 +2515,17 @@
         return 0 < getRemainingCreatableProfileCount(userType, userId, allowedToRemoveOne);
     }
 
+    @Override
+    public int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId) {
+        return getRemainingCreatableProfileCount(userType, userId, false);
+    }
+
     /**
      * Returns the remaining number of profiles of the given type that can be added to the given
      * user. (taking into account the total number of users on the device as well as how many
      * profiles exist of that type both in general and for the given user)
      */
-    @Override
-    public int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId,
+    private int getRemainingCreatableProfileCount(@NonNull String userType, @UserIdInt int userId,
             boolean allowedToRemoveOne) {
         checkQueryOrCreateUsersPermission(
                 "get the remaining number of profiles that can be added to the given user.");
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index d455be7..46fde4b 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -108,14 +108,18 @@
      * </p>
      * @param packageName The package to start a one-time permission session for
      * @param timeoutMillis Number of milliseconds for an app to be in an inactive state
+     * @param revokeAfterKilledDelayMillis Number of milliseconds to wait after the process dies
+     *                                     before ending the session. Set to -1 to use default value
+     *                                     for the device.
      * @param importanceToResetTimer The least important level to uid must be to reset the timer
      * @param importanceToKeepSessionAlive The least important level the uid must be to keep the
-     *                                    session alive
+     *                                     session alive
      *
      * @hide
      */
     void startPackageOneTimeSession(@NonNull String packageName, long timeoutMillis,
-            int importanceToResetTimer, int importanceToKeepSessionAlive) {
+            long revokeAfterKilledDelayMillis, int importanceToResetTimer,
+            int importanceToKeepSessionAlive) {
         int uid;
         try {
             uid = mContext.getPackageManager().getPackageUid(packageName, 0);
@@ -126,11 +130,15 @@
 
         synchronized (mLock) {
             PackageInactivityListener listener = mListeners.get(uid);
-            if (listener == null) {
-                listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
+            if (listener != null) {
+                listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis,
                         importanceToResetTimer, importanceToKeepSessionAlive);
-                mListeners.put(uid, listener);
+                return;
             }
+            listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
+                    revokeAfterKilledDelayMillis, importanceToResetTimer,
+                    importanceToKeepSessionAlive);
+            mListeners.put(uid, listener);
         }
     }
 
@@ -159,18 +167,6 @@
     }
 
     /**
-     * The delay to wait before revoking on the event an app is terminated. Recommended to be long
-     * enough so that apps don't lose permission on an immediate restart
-     */
-    private long getKilledDelayMillis(boolean isSelfRevokedPermissionSession) {
-        if (isSelfRevokedPermissionSession) {
-            return 0;
-        }
-        return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
-                PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS);
-    }
-
-    /**
      * Register to listen for Uids being uninstalled. This must be done outside of the
      * PermissionManagerService lock.
      */
@@ -178,18 +174,6 @@
         mContext.registerReceiver(mUninstallListener, new IntentFilter(Intent.ACTION_UID_REMOVED));
     }
 
-    void setSelfRevokedPermissionSession(int uid) {
-        synchronized (mLock) {
-            PackageInactivityListener listener = mListeners.get(uid);
-            if (listener == null) {
-                Log.e(LOG_TAG, "Could not set session for uid " + uid
-                        + " as self-revoke session: session not found");
-                return;
-            }
-            listener.setSelfRevokedPermissionSession();
-        }
-    }
-
     /**
      * A class which watches a package for inactivity and notifies the permission controller when
      * the package becomes inactive
@@ -200,11 +184,11 @@
 
         private final int mUid;
         private final @NonNull String mPackageName;
-        private final long mTimeout;
-        private final int mImportanceToResetTimer;
-        private final int mImportanceToKeepSessionAlive;
+        private long mTimeout;
+        private long mRevokeAfterKilledDelay;
+        private int mImportanceToResetTimer;
+        private int mImportanceToKeepSessionAlive;
 
-        private boolean mIsSelfRevokedPermissionSession;
         private boolean mIsAlarmSet;
         private boolean mIsFinished;
 
@@ -218,16 +202,23 @@
         private final Object mToken = new Object();
 
         private PackageInactivityListener(int uid, @NonNull String packageName, long timeout,
-                int importanceToResetTimer, int importanceToKeepSessionAlive) {
+                long revokeAfterkilledDelay, int importanceToResetTimer,
+                int importanceToKeepSessionAlive) {
 
             Log.i(LOG_TAG,
                     "Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout
+                            + " killedDelay=" + revokeAfterkilledDelay
                             + " importanceToResetTimer=" + importanceToResetTimer
                             + " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive);
 
             mUid = uid;
             mPackageName = packageName;
             mTimeout = timeout;
+            mRevokeAfterKilledDelay = revokeAfterkilledDelay == -1
+                    ? DeviceConfig.getLong(
+                            DeviceConfig.NAMESPACE_PERMISSIONS, PROPERTY_KILLED_DELAY_CONFIG_KEY,
+                            DEFAULT_KILLED_DELAY_MILLIS)
+                    : revokeAfterkilledDelay;
             mImportanceToResetTimer = importanceToResetTimer;
             mImportanceToKeepSessionAlive = importanceToKeepSessionAlive;
 
@@ -247,6 +238,28 @@
             onImportanceChanged(mUid, mActivityManager.getPackageImportance(packageName));
         }
 
+        public void updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis,
+                int importanceToResetTimer, int importanceToKeepSessionAlive) {
+            synchronized (mInnerLock) {
+                mTimeout = Math.min(mTimeout, timeoutMillis);
+                mRevokeAfterKilledDelay = Math.min(mRevokeAfterKilledDelay,
+                        revokeAfterKilledDelayMillis == -1
+                                ? DeviceConfig.getLong(
+                                DeviceConfig.NAMESPACE_PERMISSIONS,
+                                PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS)
+                                : revokeAfterKilledDelayMillis);
+                mImportanceToResetTimer = Math.min(importanceToResetTimer, mImportanceToResetTimer);
+                mImportanceToKeepSessionAlive = Math.min(importanceToKeepSessionAlive,
+                        mImportanceToKeepSessionAlive);
+                Log.v(LOG_TAG,
+                        "Updated params for " + mPackageName + ". timeout=" + mTimeout
+                                + " killedDelay=" + mRevokeAfterKilledDelay
+                                + " importanceToResetTimer=" + mImportanceToResetTimer
+                                + " importanceToKeepSessionAlive=" + mImportanceToKeepSessionAlive);
+                onImportanceChanged(mUid, mActivityManager.getPackageImportance(mPackageName));
+            }
+        }
+
         private void onImportanceChanged(int uid, int importance) {
             if (uid != mUid) {
                 return;
@@ -271,7 +284,7 @@
                             }
                             onImportanceChanged(mUid, imp);
                         }
-                    }, mToken, getKilledDelayMillis(mIsSelfRevokedPermissionSession));
+                    }, mToken, mRevokeAfterKilledDelay);
                     return;
                 }
                 if (importance > mImportanceToResetTimer) {
@@ -307,14 +320,6 @@
         }
 
         /**
-         * Marks the session as a self-revoke session, which does not delay the revocation when
-         * the app is restarting.
-         */
-        public void setSelfRevokedPermissionSession() {
-            mIsSelfRevokedPermissionSession = true;
-        }
-
-        /**
          * Set the alarm which will callback when the package is inactive
          */
         @GuardedBy("mInnerLock")
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index edc0e3d..698068d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -68,7 +68,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AndroidFuture;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.TriFunction;
 import com.android.server.LocalServices;
@@ -388,7 +387,8 @@
 
     @Override
     public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
-            long timeoutMillis, int importanceToResetTimer, int importanceToKeepSessionAlive) {
+            long timeoutMillis, long revokeAfterKilledDelayMillis, int importanceToResetTimer,
+            int importanceToKeepSessionAlive) {
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
                 "Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
@@ -398,7 +398,8 @@
         final long token = Binder.clearCallingIdentity();
         try {
             getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName,
-                    timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
+                    timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer,
+                    importanceToKeepSessionAlive);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -563,16 +564,7 @@
     @Override
     public void revokeOwnPermissionsOnKill(@NonNull String packageName,
             @NonNull List<String> permissions) {
-        final int callingUid = Binder.getCallingUid();
-        final int callingUserId = UserHandle.getUserId(callingUid);
-        AndroidFuture<Void> future = new AndroidFuture<>();
-        future.whenComplete((result, err) -> {
-            if (err == null) {
-                getOneTimePermissionUserManager(callingUserId)
-                        .setSelfRevokedPermissionSession(callingUid);
-            }
-        });
-        mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions, future);
+        mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
     }
 
     @Override
@@ -1318,7 +1310,7 @@
 
                 if (op < 0) {
                     // Bg location is one-off runtime modifier permission and has no app op
-                    if (sPlatformPermissions.contains(permission)
+                    if (sPlatformPermissions.containsKey(permission)
                             && !Manifest.permission.ACCESS_BACKGROUND_LOCATION.equals(permission)
                             && !Manifest.permission.BODY_SENSORS_BACKGROUND.equals(permission)) {
                         Slog.wtf(LOG_TAG, "Platform runtime permission " + permission
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index db9c1b5..ed351fd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -108,7 +108,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.compat.IPlatformCompat;
-import com.android.internal.infra.AndroidFuture;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.os.RoSystemProperties;
@@ -1592,8 +1591,7 @@
     }
 
     @Override
-    public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions,
-            AndroidFuture<Void> callback) {
+    public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
         final int callingUid = Binder.getCallingUid();
         int callingUserId = UserHandle.getUserId(callingUid);
         int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
@@ -1608,8 +1606,7 @@
                         + permName + " because it does not hold that permission");
             }
         }
-        mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions,
-                callback);
+        mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
     }
 
     private boolean mayManageRolePermission(int uid) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 91c558b..3e28320 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -27,7 +27,6 @@
 import android.permission.IOnPermissionsChangeListener;
 import android.permission.PermissionManagerInternal;
 
-import com.android.internal.infra.AndroidFuture;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.FileDescriptor;
@@ -338,16 +337,16 @@
      * <li>Each permission in {@code permissions} must be a runtime permission.
      * </ul>
      * <p>
-     * For every permission in {@code permissions}, the entire permission group it belongs to will
-     * be revoked. This revocation happens asynchronously and kills all processes running in the
-     * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+     * Background permissions which have no corresponding foreground permission still granted once
+     * the revocation is effective will also be revoked.
+     * <p>
+     * This revocation happens asynchronously and kills all processes running in the same UID as
+     * {@code packageName}. It will be triggered once it is safe to do so.
      *
      * @param packageName The name of the package for which the permissions will be revoked.
      * @param permissions List of permissions to be revoked.
-     * @param callback Callback called when the revocation request has been completed.
      */
-    void revokeOwnPermissionsOnKill(String packageName, List<String> permissions,
-            AndroidFuture<Void> callback);
+    void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
 
     /**
      * Get whether you should show UI with rationale for requesting a permission. You should do this
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index 25abcb3..efb6144 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -30,13 +30,13 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DataClass;
+import com.android.server.utils.Watchable;
 
 import java.util.Objects;
 
 @DataClass(genConstructor = false, genBuilder = false, genEqualsHashCode = true)
 @DataClass.Suppress({"mOverlayPathsLock", "mOverlayPaths", "mSharedLibraryOverlayPathsLock",
-        "mSharedLibraryOverlayPaths", "setOverlayPaths", "mCachedOverlayPathsLock",
-        "mCachedOverlayPaths", "setCachedOverlayPaths"})
+        "mSharedLibraryOverlayPaths", "setOverlayPaths", "setCachedOverlayPaths"})
 public class PackageUserStateImpl implements PackageUserStateInternal {
 
     @Nullable
@@ -72,31 +72,37 @@
     @Nullable
     private String mSplashScreenTheme;
 
-    /** Suspending package to suspend params */
+    /**
+     * Suspending package to suspend params
+     */
     @Nullable
     private ArrayMap<String, SuspendParams> mSuspendParams;
 
     @Nullable
-    private OverlayPaths mCachedOverlayPaths;
-
-    @Nullable
     private ArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
 
     private long mFirstInstallTime;
 
+    @Nullable
+    private final Watchable mWatchable;
+
     public PackageUserStateImpl() {
         super();
+        mWatchable = null;
     }
 
-    public PackageUserStateImpl(PackageUserStateImpl other) {
+    public PackageUserStateImpl(@NonNull Watchable watchable) {
+        mWatchable = watchable;
+    }
+
+    public PackageUserStateImpl(@NonNull Watchable watchable, PackageUserStateImpl other) {
+        mWatchable = watchable;
         mDisabledComponents = ArrayUtils.cloneOrNull(other.mDisabledComponents);
         mEnabledComponents = ArrayUtils.cloneOrNull(other.mEnabledComponents);
         mOverlayPaths = other.mOverlayPaths;
         if (other.mSharedLibraryOverlayPaths != null) {
             mSharedLibraryOverlayPaths = new ArrayMap<>(other.mSharedLibraryOverlayPaths);
         }
-        mDisabledComponents = other.mDisabledComponents;
-        mEnabledComponents = other.mEnabledComponents;
         mCeDataInode = other.mCeDataInode;
         mInstalled = other.mInstalled;
         mStopped = other.mStopped;
@@ -110,16 +116,22 @@
         mUninstallReason = other.mUninstallReason;
         mHarmfulAppWarning = other.mHarmfulAppWarning;
         mLastDisableAppCaller = other.mLastDisableAppCaller;
-        mOverlayPaths = other.mOverlayPaths;
-        mSharedLibraryOverlayPaths = other.mSharedLibraryOverlayPaths;
         mSplashScreenTheme = other.mSplashScreenTheme;
         mSuspendParams = other.mSuspendParams == null ? null : new ArrayMap<>(other.mSuspendParams);
         mComponentLabelIconOverrideMap = other.mComponentLabelIconOverrideMap == null ? null
                 : new ArrayMap<>(other.mComponentLabelIconOverrideMap);
+        mFirstInstallTime = other.mFirstInstallTime;
+    }
+
+    private void onChanged() {
+        if (mWatchable != null) {
+            mWatchable.dispatchChange(mWatchable);
+        }
     }
 
     /**
      * Sets the path of overlays currently enabled for this package and user combination.
+     *
      * @return true if the path contents differ than what they were previously
      */
     @Nullable
@@ -132,7 +144,7 @@
             return false;
         }
         mOverlayPaths = paths;
-        mCachedOverlayPaths = null;
+        onChanged();
         return true;
     }
 
@@ -150,11 +162,13 @@
         if (Objects.equals(paths, currentPaths)) {
             return false;
         }
-        mCachedOverlayPaths = null;
         if (paths == null || paths.isEmpty()) {
-            return mSharedLibraryOverlayPaths.remove(library) != null;
+            boolean returnValue = mSharedLibraryOverlayPaths.remove(library) != null;
+            onChanged();
+            return returnValue;
         } else {
             mSharedLibraryOverlayPaths.put(library, paths);
+            onChanged();
             return true;
         }
     }
@@ -233,16 +247,18 @@
 
                 mComponentLabelIconOverrideMap.put(component, Pair.create(nonLocalizedLabel, icon));
             }
+            onChanged();
         }
 
         return changed;
     }
 
     /**
-     * Clears all values previously set by {@link #overrideLabelAndIcon(ComponentName,
-     * String, Integer)}.
-     *
-     * This is done when the package is updated as the components and resource IDs may have changed.
+     * Clears all values previously set by {@link #overrideLabelAndIcon(ComponentName, String,
+     * Integer)}.
+     * <p>
+     * This is done when the package is updated as the components and resource IDs may have
+     * changed.
      */
     public void resetOverrideComponentLabelIcon() {
         mComponentLabelIconOverrideMap = null;
@@ -263,21 +279,157 @@
     }
 
     public PackageUserStateImpl putSuspendParams(@NonNull String suspendingPackage,
-            @NonNull SuspendParams suspendParams) {
+            @Nullable SuspendParams suspendParams) {
         if (mSuspendParams == null) {
             mSuspendParams = new ArrayMap<>();
         }
-        mSuspendParams.put(suspendingPackage, suspendParams);
+        if (!mSuspendParams.containsKey(suspendingPackage)
+                || !Objects.equals(mSuspendParams.get(suspendingPackage), suspendParams)) {
+            mSuspendParams.put(suspendingPackage, suspendParams);
+            onChanged();
+        }
+
         return this;
     }
 
     public PackageUserStateImpl removeSuspension(@NonNull String suspendingPackage) {
         if (mSuspendParams != null) {
             mSuspendParams.remove(suspendingPackage);
+            onChanged();
         }
         return this;
     }
 
+    public @NonNull PackageUserStateImpl setDisabledComponents(@NonNull ArraySet<String> value) {
+        mDisabledComponents = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setEnabledComponents(@NonNull ArraySet<String> value) {
+        mEnabledComponents = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setCeDataInode(long value) {
+        mCeDataInode = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setInstalled(boolean value) {
+        mInstalled = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setStopped(boolean value) {
+        mStopped = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setNotLaunched(boolean value) {
+        mNotLaunched = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setHidden(boolean value) {
+        mHidden = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setDistractionFlags(int value) {
+        mDistractionFlags = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setInstantApp(boolean value) {
+        mInstantApp = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setVirtualPreload(boolean value) {
+        mVirtualPreload = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setEnabledState(int value) {
+        mEnabledState = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setInstallReason(@PackageManager.InstallReason int value) {
+        mInstallReason = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                PackageManager.InstallReason.class, null, mInstallReason);
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setUninstallReason(
+            @PackageManager.UninstallReason int value) {
+        mUninstallReason = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                PackageManager.UninstallReason.class, null, mUninstallReason);
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setHarmfulAppWarning(@NonNull String value) {
+        mHarmfulAppWarning = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setLastDisableAppCaller(@NonNull String value) {
+        mLastDisableAppCaller = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setSharedLibraryOverlayPaths(
+            @NonNull ArrayMap<String, OverlayPaths> value) {
+        mSharedLibraryOverlayPaths = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setSplashScreenTheme(@NonNull String value) {
+        mSplashScreenTheme = value;
+        onChanged();
+        return this;
+    }
+
+    /**
+     * Suspending package to suspend params
+     */
+    public @NonNull PackageUserStateImpl setSuspendParams(
+            @NonNull ArrayMap<String, SuspendParams> value) {
+        mSuspendParams = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setComponentLabelIconOverrideMap(
+            @NonNull ArrayMap<ComponentName, Pair<String, Integer>> value) {
+        mComponentLabelIconOverrideMap = value;
+        onChanged();
+        return this;
+    }
+
+    public @NonNull PackageUserStateImpl setFirstInstallTime(long value) {
+        mFirstInstallTime = value;
+        onChanged();
+        return this;
+    }
 
 
 
@@ -393,11 +545,6 @@
     }
 
     @DataClass.Generated.Member
-    public @Nullable OverlayPaths getCachedOverlayPaths() {
-        return mCachedOverlayPaths;
-    }
-
-    @DataClass.Generated.Member
     public @Nullable ArrayMap<ComponentName,Pair<String,Integer>> getComponentLabelIconOverrideMap() {
         return mComponentLabelIconOverrideMap;
     }
@@ -408,130 +555,8 @@
     }
 
     @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setDisabledComponents(@NonNull ArraySet<String> value) {
-        mDisabledComponents = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setEnabledComponents(@NonNull ArraySet<String> value) {
-        mEnabledComponents = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setCeDataInode( long value) {
-        mCeDataInode = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setInstalled( boolean value) {
-        mInstalled = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setStopped( boolean value) {
-        mStopped = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setNotLaunched( boolean value) {
-        mNotLaunched = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setHidden( boolean value) {
-        mHidden = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setDistractionFlags( int value) {
-        mDistractionFlags = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setInstantApp( boolean value) {
-        mInstantApp = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setVirtualPreload( boolean value) {
-        mVirtualPreload = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setEnabledState( int value) {
-        mEnabledState = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setInstallReason(@PackageManager.InstallReason int value) {
-        mInstallReason = value;
-        com.android.internal.util.AnnotationValidations.validate(
-                PackageManager.InstallReason.class, null, mInstallReason);
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setUninstallReason(@PackageManager.UninstallReason int value) {
-        mUninstallReason = value;
-        com.android.internal.util.AnnotationValidations.validate(
-                PackageManager.UninstallReason.class, null, mUninstallReason);
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setHarmfulAppWarning(@NonNull String value) {
-        mHarmfulAppWarning = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setLastDisableAppCaller(@NonNull String value) {
-        mLastDisableAppCaller = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setSharedLibraryOverlayPaths(@NonNull ArrayMap<String,OverlayPaths> value) {
-        mSharedLibraryOverlayPaths = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setSplashScreenTheme(@NonNull String value) {
-        mSplashScreenTheme = value;
-        return this;
-    }
-
-    /**
-     * Suspending package to suspend params
-     */
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setSuspendParams(@NonNull ArrayMap<String,SuspendParams> value) {
-        mSuspendParams = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setComponentLabelIconOverrideMap(@NonNull ArrayMap<ComponentName,Pair<String,Integer>> value) {
-        mComponentLabelIconOverrideMap = value;
-        return this;
-    }
-
-    @DataClass.Generated.Member
-    public @NonNull PackageUserStateImpl setFirstInstallTime( long value) {
-        mFirstInstallTime = value;
-        return this;
+    public @Nullable Watchable getWatchable() {
+        return mWatchable;
     }
 
     @Override
@@ -566,9 +591,9 @@
                 && Objects.equals(mSharedLibraryOverlayPaths, that.mSharedLibraryOverlayPaths)
                 && Objects.equals(mSplashScreenTheme, that.mSplashScreenTheme)
                 && Objects.equals(mSuspendParams, that.mSuspendParams)
-                && Objects.equals(mCachedOverlayPaths, that.mCachedOverlayPaths)
                 && Objects.equals(mComponentLabelIconOverrideMap, that.mComponentLabelIconOverrideMap)
-                && mFirstInstallTime == that.mFirstInstallTime;
+                && mFirstInstallTime == that.mFirstInstallTime
+                && Objects.equals(mWatchable, that.mWatchable);
     }
 
     @Override
@@ -597,17 +622,17 @@
         _hash = 31 * _hash + Objects.hashCode(mSharedLibraryOverlayPaths);
         _hash = 31 * _hash + Objects.hashCode(mSplashScreenTheme);
         _hash = 31 * _hash + Objects.hashCode(mSuspendParams);
-        _hash = 31 * _hash + Objects.hashCode(mCachedOverlayPaths);
         _hash = 31 * _hash + Objects.hashCode(mComponentLabelIconOverrideMap);
         _hash = 31 * _hash + Long.hashCode(mFirstInstallTime);
+        _hash = 31 * _hash + Objects.hashCode(mWatchable);
         return _hash;
     }
 
     @DataClass.Generated(
-            time = 1640923839971L,
+            time = 1643854846064L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
-            inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate  long mCeDataInode\nprivate  boolean mInstalled\nprivate  boolean mStopped\nprivate  boolean mNotLaunched\nprivate  boolean mHidden\nprivate  int mDistractionFlags\nprivate  boolean mInstantApp\nprivate  boolean mVirtualPreload\nprivate  int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mCachedOverlayPaths\nprivate @android.annotation.Nullable android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate  long mFirstInstallTime\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic  boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic  void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic  com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic  com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\nclass PackageUserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserStateInternal]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+            inputSignatures = "protected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mDisabledComponents\nprotected @android.annotation.Nullable android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate  long mCeDataInode\nprivate  boolean mInstalled\nprivate  boolean mStopped\nprivate  boolean mNotLaunched\nprivate  boolean mHidden\nprivate  int mDistractionFlags\nprivate  boolean mInstantApp\nprivate  boolean mVirtualPreload\nprivate  int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprotected @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate  long mFirstInstallTime\nprivate final @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate  void onChanged()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic  boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic  void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic  com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic  com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTime(long)\nclass PackageUserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserStateInternal]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemService.java b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemService.java
index 586d2c4..cf478b1 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemService.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemService.java
@@ -34,4 +34,7 @@
 
     @Nullable
     String getMaxSdkVersion();
+
+    int getInitOrder();
+
 }
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
index 1e427d0..167aba3 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
@@ -48,18 +48,18 @@
     @Nullable
     private String maxSdkVersion;
 
+    private int initOrder;
+
     public ParsedApexSystemServiceImpl() {
     }
 
-
-
     // 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/content/pm/parsing/component/ParsedApexSystemServiceImpl.java
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -71,13 +71,15 @@
             @NonNull String name,
             @Nullable String jarPath,
             @Nullable String minSdkVersion,
-            @Nullable String maxSdkVersion) {
+            @Nullable String maxSdkVersion,
+            int initOrder) {
         this.name = name;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, name);
         this.jarPath = jarPath;
         this.minSdkVersion = minSdkVersion;
         this.maxSdkVersion = maxSdkVersion;
+        this.initOrder = initOrder;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -103,6 +105,11 @@
     }
 
     @DataClass.Generated.Member
+    public int getInitOrder() {
+        return initOrder;
+    }
+
+    @DataClass.Generated.Member
     public @NonNull ParsedApexSystemServiceImpl setName(@NonNull String value) {
         name = value;
         com.android.internal.util.AnnotationValidations.validate(
@@ -129,6 +136,12 @@
     }
 
     @DataClass.Generated.Member
+    public @NonNull ParsedApexSystemServiceImpl setInitOrder( int value) {
+        initOrder = value;
+        return this;
+    }
+
+    @DataClass.Generated.Member
     static Parcelling<String> sParcellingForName =
             Parcelling.Cache.get(
                     Parcelling.BuiltIn.ForInternedString.class);
@@ -187,6 +200,7 @@
         sParcellingForJarPath.parcel(jarPath, dest, flags);
         sParcellingForMinSdkVersion.parcel(minSdkVersion, dest, flags);
         sParcellingForMaxSdkVersion.parcel(maxSdkVersion, dest, flags);
+        dest.writeInt(initOrder);
     }
 
     @Override
@@ -205,6 +219,7 @@
         String _jarPath = sParcellingForJarPath.unparcel(in);
         String _minSdkVersion = sParcellingForMinSdkVersion.unparcel(in);
         String _maxSdkVersion = sParcellingForMaxSdkVersion.unparcel(in);
+        int _initOrder = in.readInt();
 
         this.name = _name;
         com.android.internal.util.AnnotationValidations.validate(
@@ -212,6 +227,7 @@
         this.jarPath = _jarPath;
         this.minSdkVersion = _minSdkVersion;
         this.maxSdkVersion = _maxSdkVersion;
+        this.initOrder = _initOrder;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -231,10 +247,10 @@
     };
 
     @DataClass.Generated(
-            time = 1641431950080L,
+            time = 1643723578605L,
             codegenVersion = "1.0.23",
-            sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java",
-            inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedApexSystemService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)")
+            sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java",
+            inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nprivate  int initOrder\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [com.android.server.pm.pkg.component.ParsedApexSystemService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
index 38a6f5a35..ed9aa2e 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
@@ -53,10 +53,13 @@
                     R.styleable.AndroidManifestApexSystemService_minSdkVersion);
             String maxSdkVersion = sa.getString(
                     R.styleable.AndroidManifestApexSystemService_maxSdkVersion);
+            int initOrder = sa.getInt(R.styleable.AndroidManifestApexSystemService_initOrder, 0);
 
             systemService.setName(className)
                     .setMinSdkVersion(minSdkVersion)
-                    .setMaxSdkVersion(maxSdkVersion);
+                    .setMaxSdkVersion(maxSdkVersion)
+                    .setInitOrder(initOrder);
+
             if (!TextUtils.isEmpty(jarPath)) {
                 systemService.setJarPath(jarPath);
             }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7dd9425..7e36290 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -27,6 +27,7 @@
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS;
 import static android.os.Build.VERSION_CODES.M;
 import static android.os.Build.VERSION_CODES.O;
 import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
@@ -129,6 +130,7 @@
 import android.media.AudioSystem;
 import android.media.IAudioService;
 import android.media.session.MediaSessionLegacyHelper;
+import android.os.BatteryManagerInternal;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.DeviceIdleManager;
@@ -392,11 +394,12 @@
     PowerManagerInternal mPowerManagerInternal;
     IStatusBarService mStatusBarService;
     StatusBarManagerInternal mStatusBarManagerInternal;
+    BatteryManagerInternal mBatteryManagerInternal;
     AudioManagerInternal mAudioManagerInternal;
     DisplayManager mDisplayManager;
     DisplayManagerInternal mDisplayManagerInternal;
     boolean mPreloadedRecentApps;
-    final Object mServiceAquireLock = new Object();
+    final Object mServiceAcquireLock = new Object();
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
     SearchManager mSearchManager;
     AccessibilityManager mAccessibilityManager;
@@ -782,7 +785,8 @@
         @Override
         public void onWakeUp() {
             synchronized (mLock) {
-                if (shouldEnableWakeGestureLp()) {
+                if (shouldEnableWakeGestureLp()
+                        && mBatteryManagerInternal.getPlugType() != BATTERY_PLUGGED_WIRELESS) {
                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
                             "Wake Up");
                     wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
@@ -811,7 +815,7 @@
     }
 
     IStatusBarService getStatusBarService() {
-        synchronized (mServiceAquireLock) {
+        synchronized (mServiceAcquireLock) {
             if (mStatusBarService == null) {
                 mStatusBarService = IStatusBarService.Stub.asInterface(
                         ServiceManager.getService("statusbar"));
@@ -821,7 +825,7 @@
     }
 
     StatusBarManagerInternal getStatusBarManagerInternal() {
-        synchronized (mServiceAquireLock) {
+        synchronized (mServiceAcquireLock) {
             if (mStatusBarManagerInternal == null) {
                 mStatusBarManagerInternal =
                         LocalServices.getService(StatusBarManagerInternal.class);
@@ -831,7 +835,7 @@
     }
 
     AudioManagerInternal getAudioManagerInternal() {
-        synchronized (mServiceAquireLock) {
+        synchronized (mServiceAcquireLock) {
             if (mAudioManagerInternal == null) {
                 mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
             }
@@ -839,6 +843,15 @@
         }
     }
 
+    BatteryManagerInternal getBatteryManagerInternal() {
+        synchronized (mServiceAcquireLock) {
+            if (mBatteryManagerInternal == null) {
+                mBatteryManagerInternal =
+                        LocalServices.getService(BatteryManagerInternal.class);
+            }
+            return mBatteryManagerInternal;
+        }
+    }
 
     // returns true if the key was handled and should not be passed to the user
     private boolean backKeyPress() {
diff --git a/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java b/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java
new file mode 100644
index 0000000..750d400
--- /dev/null
+++ b/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2022 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.sensorprivacy;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightState;
+import android.hardware.lights.LightsManager;
+import android.hardware.lights.LightsRequest;
+import android.permission.PermissionManager;
+import android.util.ArraySet;
+
+import com.android.internal.R;
+import com.android.server.FgThread;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+class CameraPrivacyLightController implements AppOpsManager.OnOpActiveChangedListener {
+
+    private final Context mContext;
+    private final LightsManager mLightsManager;
+
+    private final Set<String> mActivePackages = new ArraySet<>();
+    private final Set<String> mActivePhonePackages = new ArraySet<>();
+
+    private final int mCameraPrivacyLightColor;
+
+    private final List<Light> mCameraLights = new ArrayList<>();
+    private final AppOpsManager mAppOpsManager;
+
+    private LightsManager.LightsSession mLightsSession = null;
+
+    CameraPrivacyLightController(Context context) {
+        mContext = context;
+
+        mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+        mLightsManager = mContext.getSystemService(LightsManager.class);
+
+        mCameraPrivacyLightColor = mContext.getColor(R.color.camera_privacy_light);
+
+        List<Light> lights = mLightsManager.getLights();
+        for (int i = 0; i < lights.size(); i++) {
+            Light light = lights.get(i);
+            if (light.getType() == Light.LIGHT_TYPE_CAMERA) {
+                mCameraLights.add(light);
+            }
+        }
+
+        if (mCameraLights.isEmpty()) {
+            return;
+        }
+
+        mAppOpsManager.startWatchingActive(
+                new String[] {AppOpsManager.OPSTR_CAMERA, AppOpsManager.OPSTR_PHONE_CALL_CAMERA},
+                FgThread.getExecutor(), this);
+    }
+
+    @Override
+    public void onOpActiveChanged(String op, int uid, String packageName, boolean active) {
+        final Set<String> activePackages;
+        if (AppOpsManager.OPSTR_CAMERA.equals(op)) {
+            activePackages = mActivePackages;
+        } else if (AppOpsManager.OPSTR_PHONE_CALL_CAMERA.equals(op)) {
+            activePackages = mActivePhonePackages;
+        } else {
+            return;
+        }
+
+        if (active) {
+            activePackages.add(packageName);
+        } else {
+            activePackages.remove(packageName);
+        }
+
+        updateLightSession();
+    }
+
+    private void updateLightSession() {
+        Set<String> exemptedPackages = PermissionManager.getIndicatorExemptedPackages(mContext);
+
+        boolean shouldSessionEnd = exemptedPackages.containsAll(mActivePackages)
+                && exemptedPackages.containsAll(mActivePhonePackages);
+
+        if (shouldSessionEnd) {
+            if (mLightsSession == null) {
+                return;
+            }
+
+            mLightsSession.close();
+            mLightsSession = null;
+        } else {
+            if (mLightsSession != null) {
+                return;
+            }
+
+            LightsRequest.Builder requestBuilder = new LightsRequest.Builder();
+            for (int i = 0; i < mCameraLights.size(); i++) {
+                requestBuilder.addLight(mCameraLights.get(i),
+                        new LightState.Builder()
+                                .setColor(mCameraPrivacyLightColor)
+                                .build());
+            }
+
+            mLightsSession = mLightsManager.openSession(Integer.MAX_VALUE);
+            mLightsSession.requestLights(requestBuilder.build());
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index e9b5f11..040fffa8 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -154,6 +154,8 @@
     private final AppOpsManagerInternal mAppOpsManagerInternal;
     private final TelephonyManager mTelephonyManager;
 
+    private CameraPrivacyLightController mCameraPrivacyLightController;
+
     private final IBinder mAppOpsRestrictionToken = new Binder();
 
     private SensorPrivacyManagerInternalImpl mSensorPrivacyManagerInternal;
@@ -190,6 +192,8 @@
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
             mEmergencyCallHelper = new EmergencyCallHelper();
+        } else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
+            mCameraPrivacyLightController = new CameraPrivacyLightController(mContext);
         }
     }
 
diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
index 21d4cbb..f4b335e 100644
--- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
+++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
@@ -365,6 +365,20 @@
         }
 
         @Override
+        public void onSegmentResults(Bundle results) throws RemoteException {
+            mRemoteListener.onSegmentResults(results);
+        }
+
+        @Override
+        public void onEndOfSegmentedSession() throws RemoteException {
+            if (DEBUG) {
+                Slog.i(TAG, "#onEndOfSegmentedSession invoked for a recognition session");
+            }
+            mOnSessionComplete.run();
+            mRemoteListener.onEndOfSegmentedSession();
+        }
+
+        @Override
         public void onEvent(int eventType, Bundle params) throws RemoteException {
             mRemoteListener.onEvent(eventType, params);
         }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index ee2cc7b..56985af 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2591,8 +2591,20 @@
      */
     @Override
     public void setWallpaperDimAmount(float dimAmount) throws RemoteException {
+        setWallpaperDimAmountForUid(Binder.getCallingUid(), dimAmount);
+    }
+
+    /**
+     * Sets wallpaper dim amount for a given UID. This only applies to FLAG_SYSTEM wallpaper as the
+     * lock screen does not have a wallpaper component, so we use mWallpaperMap.
+     *
+     * @param uid Caller UID that wants to set the wallpaper dim amount
+     * @param dimAmount Dim amount where 0f reverts any dimming applied by the caller (fully bright)
+     *                  and 1f is fully black
+     * @throws RemoteException
+     */
+    public void setWallpaperDimAmountForUid(int uid, float dimAmount) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_DIM_AMOUNT);
-        int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerShellCommand.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerShellCommand.java
index fc827b4..458bf20 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerShellCommand.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerShellCommand.java
@@ -43,6 +43,8 @@
         switch(cmd) {
             case "set-dim-amount":
                 return setWallpaperDimAmount();
+            case "dim-with-uid":
+                return setDimmingWithUid();
             case "get-dim-amount":
                 return getWallpaperDimAmount();
             case "-h":
@@ -64,6 +66,10 @@
         pw.println("  set-dim-amount DIMMING");
         pw.println("    Sets the current dimming value to DIMMING (a number between 0 and 1).");
         pw.println();
+        pw.println("  dim-with-uid UID DIMMING");
+        pw.println("    Sets the wallpaper dim amount to DIMMING as if an app with uid, UID, "
+                + "called it.");
+        pw.println();
         pw.println("  get-dim-amount");
         pw.println("    Get the current wallpaper dim amount.");
     }
@@ -92,4 +98,17 @@
         getOutPrintWriter().println("The current wallpaper dim amount is: " + dimAmount);
         return 0;
     }
+
+    /**
+     * Sets the wallpaper dim amount for an arbitrary UID to simulate multiple applications setting
+     * a dim amount on the wallpaper.
+     */
+    private int setDimmingWithUid() {
+        int mockUid = Integer.parseInt(getNextArgRequired());
+        float mockDimAmount = Float.parseFloat(getNextArgRequired());
+        mService.setWallpaperDimAmountForUid(mockUid, mockDimAmount);
+        getOutPrintWriter().println("Dimming the wallpaper for UID: " + mockUid + " to: "
+                + mockDimAmount);
+        return 0;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5f04b7e..6836e31 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7655,13 +7655,15 @@
      *     <li>{@link LetterboxConfiguration#getIsEducationEnabled} is true.
      *     <li>The activity is eligible for fixed orientation letterbox.
      *     <li>The activity is in fullscreen.
+     *     <li>The activity is portrait-only.
      * </ul>
      */
     // TODO(b/215316431): Add tests
     boolean isEligibleForLetterboxEducation() {
         return mWmService.mLetterboxConfiguration.getIsEducationEnabled()
                 && mIsEligibleForFixedOrientationLetterbox
-                && getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
+                && getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+                && getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 8d4ae90..ca4d717 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -24,6 +24,7 @@
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
+import static android.Manifest.permission.MANAGE_GAME_ACTIVITY;
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.REMOVE_TASKS;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
@@ -1771,6 +1772,43 @@
     }
 
     @Override
+    public int startActivityFromGameSession(IApplicationThread caller, String callingPackage,
+            String callingFeatureId, int callingPid, int callingUid, Intent intent, int taskId,
+            int userId) {
+        if (checkCallingPermission(MANAGE_GAME_ACTIVITY) != PERMISSION_GRANTED) {
+            final String msg = "Permission Denial: startActivityFromGameSession() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + MANAGE_GAME_ACTIVITY;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        assertPackageMatchesCallingUid(callingPackage);
+
+        final ActivityOptions activityOptions = ActivityOptions.makeBasic();
+        activityOptions.setLaunchTaskId(taskId);
+
+        userId = handleIncomingUser(callingPid, callingUid, userId, "startActivityFromGameSession");
+
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            return getActivityStartController()
+                    .obtainStarter(intent, "startActivityFromGameSession")
+                    .setCaller(caller)
+                    .setCallingUid(callingUid)
+                    .setCallingPid(callingPid)
+                    .setCallingPackage(intent.getPackage())
+                    .setCallingFeatureId(callingFeatureId)
+                    .setUserId(userId)
+                    .setActivityOptions(activityOptions.toBundle())
+                    .setRealCallingUid(Binder.getCallingUid())
+                    .execute();
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
     public BackNavigationInfo startBackNavigation() {
         mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
                 "startBackNavigation()");
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index a8779fa..45a6cb9 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -29,6 +29,7 @@
 import android.util.Slog;
 import android.view.SurfaceControl;
 import android.window.BackNavigationInfo;
+import android.window.IOnBackInvokedCallback;
 import android.window.TaskSnapshot;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -91,29 +92,41 @@
         HardwareBuffer screenshotBuffer = null;
         int prevTaskId;
         int prevUserId;
+        IOnBackInvokedCallback callback;
 
         synchronized (task.mWmService.mGlobalLock) {
             activityRecord = task.topRunningActivity();
             removedWindowContainer = activityRecord;
             taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration;
 
-            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, topRunningActivity=%s",
-                    task, activityRecord);
+            WindowState topChild = activityRecord.getTopChild();
+            callback = topChild.getOnBackInvokedCallback();
 
-            // IME is visible, back gesture will dismiss it, nothing to preview.
-            if (task.getDisplayContent().getImeContainer().isVisible()) {
-                return null;
-            }
+            ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, "
+                            + "topRunningActivity=%s, topWindow=%s backCallback=%s",
+                    task, activityRecord, topChild,
+                    callback != null ? callback.getClass().getSimpleName() : null);
 
-            // Current Activity is home, there is no previous activity to display
-            if (activityRecord.isActivityTypeHome()) {
-                return null;
+            // For IME and Home, either a callback is registered, or we do nothing. In both cases,
+            // we don't need to pass the leashes below.
+            if (task.getDisplayContent().getImeContainer().isVisible()
+                    || activityRecord.isActivityTypeHome()) {
+                if (callback != null) {
+                    return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
+                            null /* topWindowLeash */, null /* screenshotSurface */,
+                            null /* screenshotBuffer */, null /* taskWindowConfiguration */,
+                            null /* onBackNavigationDone */, callback /* onBackInvokedCallback */);
+                } else {
+                    return null;
+                }
             }
 
             prev = task.getActivity(
                     (r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());
 
-            if (prev != null) {
+            if (callback != null) {
+                backType = BackNavigationInfo.TYPE_CALLBACK;
+            } else if (prev != null) {
                 backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
             } else if (task.returnsToHomeRootTask()) {
                 prevTask = null;
@@ -148,7 +161,7 @@
 
             // Prepare a leash to animate the current top window
             animLeash = removedWindowContainer.makeAnimationLeash()
-                    .setName("BackPreview Leash")
+                    .setName("BackPreview Leash for " + removedWindowContainer)
                     .setHidden(false)
                     .setBLASTLayer()
                     .build();
@@ -158,7 +171,7 @@
         }
 
         SurfaceControl.Builder builder = new SurfaceControl.Builder()
-                .setName("BackPreview Screenshot")
+                .setName("BackPreview Screenshot for " + prev)
                 .setParent(animationLeashParent)
                 .setHidden(false)
                 .setBLASTLayer();
@@ -171,6 +184,10 @@
                 screenshotBuffer = getTaskSnapshot(prevTaskId, prevUserId);
             }
         }
+
+        // The Animation leash needs to be above the screenshot surface, but the animation leash
+        // needs to be added before to be in the synchronized block.
+        tx.setLayer(animLeash, 1);
         tx.apply();
 
         WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
@@ -183,13 +200,16 @@
             return null;
         }
 
+        RemoteCallback onBackNavigationDone = new RemoteCallback(
+                result -> resetSurfaces(finalRemovedWindowContainer
+                ));
         return new BackNavigationInfo(backType,
                 animLeash,
                 screenshotSurface,
                 screenshotBuffer,
                 taskWindowConfiguration,
-                new RemoteCallback(result -> resetSurfaces(finalRemovedWindowContainer
-                )));
+                onBackNavigationDone,
+                callback);
     }
 
 
diff --git a/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java b/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java
index 0cd3680..f3be66c 100644
--- a/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java
+++ b/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java
@@ -106,14 +106,18 @@
 
     private void updateConfig(int uid, String packageName) {
         final ArraySet<WindowProcessController> processes = mAtm.mProcessMap.getProcesses(uid);
-        if (processes == null) return;
+        if (processes == null || processes.isEmpty()) return;
+        LocaleList localesOverride = LocaleOverlayHelper.combineLocalesIfOverlayExists(
+                mLocales, mAtm.getGlobalConfiguration().getLocales());
         for (int i = processes.size() - 1; i >= 0; i--) {
             final WindowProcessController wpc = processes.valueAt(i);
-            if (!wpc.mInfo.packageName.equals(packageName)) continue;
-            LocaleList localesOverride = LocaleOverlayHelper.combineLocalesIfOverlayExists(
-                    mLocales, mAtm.getGlobalConfiguration().getLocales());
-            wpc.applyAppSpecificConfig(mNightMode, localesOverride);
-            wpc.updateAppSpecificSettingsForAllActivities(mNightMode, localesOverride);
+            if (wpc.mInfo.packageName.equals(packageName)) {
+                wpc.applyAppSpecificConfig(mNightMode, localesOverride);
+            }
+            // Always inform individual activities about the update, since activities from other
+            // packages may be sharing this process
+            wpc.updateAppSpecificSettingsForAllActivitiesInPackage(packageName, mNightMode,
+                    localesOverride);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 2ae2b43..f26c5393 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -885,8 +885,16 @@
     }
 
     @Override
-    public void setOnBackInvokedCallback(IWindow iWindow,
-            IOnBackInvokedCallback iOnBackInvokedCallback) throws RemoteException {
-        // TODO: Set the callback to the WindowState of the window.
+    public void setOnBackInvokedCallback(IWindow window,
+            IOnBackInvokedCallback onBackInvokedCallback) throws RemoteException {
+        synchronized (mService.mGlobalLock) {
+            WindowState windowState = mService.windowForClientLocked(this, window, false);
+            if (windowState == null) {
+                Slog.e(TAG_WM,
+                        "setOnBackInvokedCallback(): Can't find window state for window:" + window);
+            } else {
+                windowState.setOnBackInvokedCallback(onBackInvokedCallback);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 97735a2..b84ef77 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2197,10 +2197,6 @@
             final Rect taskBounds = getBounds();
             width = taskBounds.width();
             height = taskBounds.height();
-
-            final int outset = getTaskOutset();
-            width += 2 * outset;
-            height += 2 * outset;
         }
         if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
             return;
@@ -2209,28 +2205,6 @@
         mLastSurfaceSize.set(width, height);
     }
 
-    /**
-     * Calculate an amount by which to expand the task bounds in each direction.
-     * Used to make room for shadows in the pinned windowing mode.
-     */
-    int getTaskOutset() {
-        // If we are drawing shadows on the task then don't outset the root task.
-        if (mWmService.mRenderShadowsInCompositor) {
-            return 0;
-        }
-        DisplayContent displayContent = getDisplayContent();
-        if (inPinnedWindowingMode() && displayContent != null) {
-            final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
-
-            // We multiply by two to match the client logic for converting view elevation
-            // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets}
-            return (int) Math.ceil(
-                    mWmService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, displayMetrics)
-                            * 2);
-        }
-        return 0;
-    }
-
     @VisibleForTesting
     Point getLastSurfaceSize() {
         return mLastSurfaceSize;
@@ -4338,7 +4312,7 @@
      */
     private void updateShadowsRadius(boolean taskIsFocused,
             SurfaceControl.Transaction pendingTransaction) {
-        if (!mWmService.mRenderShadowsInCompositor || !isRootTask()) return;
+        if (!isRootTask()) return;
 
         final float newShadowRadius = getShadowRadius(taskIsFocused);
         if (mShadowRadius != newShadowRadius) {
@@ -6015,14 +5989,6 @@
         scheduleAnimation();
     }
 
-    @Override
-    void getRelativePosition(Point outPos) {
-        super.getRelativePosition(outPos);
-        final int outset = getTaskOutset();
-        outPos.x -= outset;
-        outPos.y -= outset;
-    }
-
     private Point getRelativePosition() {
         Point position = new Point();
         getRelativePosition(position);
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index ad45948..155db2c 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1082,6 +1082,10 @@
             for (WindowContainer<?> p = wc.getParent(); p != null; p = p.getParent()) {
                 final ChangeInfo parentChange = changes.get(p);
                 if (parentChange == null || !parentChange.hasChanged(p)) break;
+                if (p.mRemoteToken == null) {
+                    // Intermediate parents must be those that has window to be managed by Shell.
+                    continue;
+                }
                 if (parentChange.mParent != null && !skipIntermediateReports) {
                     changes.get(wc).mParent = p;
                     // The chain above the parent was processed.
diff --git a/services/core/java/com/android/server/wm/OverlayHost.java b/services/core/java/com/android/server/wm/TrustedOverlayHost.java
similarity index 89%
rename from services/core/java/com/android/server/wm/OverlayHost.java
rename to services/core/java/com/android/server/wm/TrustedOverlayHost.java
index 90f5b09..975b21c 100644
--- a/services/core/java/com/android/server/wm/OverlayHost.java
+++ b/services/core/java/com/android/server/wm/TrustedOverlayHost.java
@@ -32,14 +32,20 @@
  *
  * Also handles multiplexing of event dispatch and tracking of overlays
  * to make things easier for WindowContainer.
+ *
+ * These overlays are to be used for various types of System UI and UI
+ * under the systems control. Provided SurfacePackages will be able
+ * to overlay application content, without engaging the usual cross process
+ * obscured touch filtering mechanisms. It's imperative that all UI provided
+ * be under complete control of the system.
  */
-class OverlayHost {
+class TrustedOverlayHost {
     // Lazily initialized when required
     SurfaceControl mSurfaceControl;
     final ArrayList<SurfaceControlViewHost.SurfacePackage> mOverlays = new ArrayList<>();
     final WindowManagerService mWmService;
 
-    OverlayHost(WindowManagerService wms) {
+    TrustedOverlayHost(WindowManagerService wms) {
         mWmService = wms;
     }
 
@@ -51,6 +57,8 @@
                 .setName("Overlay Host Leash");
 
             mSurfaceControl = b.build();
+            SurfaceControl.Transaction t = mWmService.mTransactionFactory.get();
+            t.setTrustedOverlay(mSurfaceControl, true).apply();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 1bd153b..8a373bf 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -314,7 +314,7 @@
 
     private final List<WindowContainerListener> mListeners = new ArrayList<>();
 
-    protected OverlayHost mOverlayHost;
+    protected TrustedOverlayHost mOverlayHost;
 
     WindowContainer(WindowManagerService wms) {
         mWmService = wms;
@@ -3600,9 +3600,9 @@
                 @AnimationType int type, @Nullable AnimationAdapter snapshotAnim);
     }
 
-    void addOverlay(SurfaceControlViewHost.SurfacePackage overlay) {
+    void addTrustedOverlay(SurfaceControlViewHost.SurfacePackage overlay) {
         if (mOverlayHost == null) {
-            mOverlayHost = new OverlayHost(mWmService);
+            mOverlayHost = new TrustedOverlayHost(mWmService);
         }
         mOverlayHost.addOverlay(overlay, mSurfaceControl);
 
@@ -3613,11 +3613,11 @@
             overlay.getRemoteInterface().onConfigurationChanged(getConfiguration());
         } catch (Exception e) {
             Slog.e(TAG, "Error sending initial configuration change to WindowContainer overlay");
-            removeOverlay(overlay);
+            removeTrustedOverlay(overlay);
         }
     }
 
-    void removeOverlay(SurfaceControlViewHost.SurfacePackage overlay) {
+    void removeTrustedOverlay(SurfaceControlViewHost.SurfacePackage overlay) {
         if (mOverlayHost != null && !mOverlayHost.removeOverlay(overlay)) {
             mOverlayHost.release();
             mOverlayHost = null;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 4900f929..9585a4b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -827,6 +827,11 @@
      * Internal methods for other parts of SystemServer to manage
      * SurfacePackage based overlays on tasks.
      *
+     * Since these overlays will overlay application content, they exist
+     * in a container with setTrustedOverlay(true). This means its imperative
+     * that this overlay feature only be used with UI completely under the control
+     * of the system, without 3rd party content.
+     *
      * Callers prepare a view hierarchy with SurfaceControlViewHost
      * and send the package to WM here. The remote view hierarchy will receive
      * configuration change, lifecycle events, etc, forwarded over the
@@ -837,8 +842,10 @@
      * The embedded hierarchy exists in a coordinate space relative to the task
      * bounds.
      */
-    public abstract void addTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay);
-    public abstract void removeTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay);
+    public abstract void addTrustedTaskOverlay(int taskId,
+            SurfaceControlViewHost.SurfacePackage overlay);
+    public abstract void removeTrustedTaskOverlay(int taskId,
+            SurfaceControlViewHost.SurfacePackage overlay);
 
     /**
      * Get a SurfaceControl that is the container layer that should be used to receive input to
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1167cb5..c9c3f1d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -21,6 +21,7 @@
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
+import static android.Manifest.permission.MODIFY_TOUCH_MODE_STATE;
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
 import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
@@ -38,6 +39,7 @@
 import static android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.myPid;
+import static android.os.Process.myUid;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW;
@@ -462,11 +464,6 @@
     int mVr2dDisplayId = INVALID_DISPLAY;
     boolean mVrModeEnabled = false;
 
-    /* If true, shadows drawn around the window will be rendered by the system compositor. If
-     * false, shadows will be drawn by the client by setting an elevation on the root view and
-     * the contents will be inset by the shadow radius. */
-    boolean mRenderShadowsInCompositor = false;
-
     /**
      * Tracks a map of input tokens to info that is used to decide whether to intercept
      * a key event.
@@ -711,6 +708,7 @@
     final static int WINDOWS_FREEZING_SCREENS_TIMEOUT = 2;
     int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
 
+    /** Indicates that the system server is actively demanding the screen be frozen. */
     boolean mClientFreezingScreen = false;
     int mAppsFreezingScreen = 0;
 
@@ -811,8 +809,6 @@
             resolver.registerContentObserver(mForceResizableUri, false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(mDevEnableNonResizableMultiWindowUri, false, this,
                     UserHandle.USER_ALL);
-            resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
-                    UserHandle.USER_ALL);
             resolver.registerContentObserver(mDisplaySettingsPathUri, false, this,
                     UserHandle.USER_ALL);
         }
@@ -853,11 +849,6 @@
                 return;
             }
 
-            if (mRenderShadowsInCompositorUri.equals(uri)) {
-                setShadowRenderer();
-                return;
-            }
-
             if (mDisplaySettingsPathUri.equals(uri)) {
                 updateDisplaySettingsLocation();
                 return;
@@ -972,11 +963,6 @@
         }
     }
 
-    private void setShadowRenderer() {
-        mRenderShadowsInCompositor = Settings.Global.getInt(mContext.getContentResolver(),
-                DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
-    }
-
     PowerManager mPowerManager;
     PowerManagerInternal mPowerManagerInternal;
 
@@ -1202,7 +1188,8 @@
                 com.android.internal.R.bool.config_hasPermanentDpad);
         mInTouchMode = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_defaultInTouchMode);
-        inputManager.setInTouchMode(mInTouchMode);
+        inputManager.setInTouchMode(
+                mInTouchMode, myPid(), myUid(), /* hasPermission = */ true);
         mDrawLockTimeoutMillis = context.getResources().getInteger(
                 com.android.internal.R.integer.config_drawLockTimeoutMillis);
         mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(
@@ -1395,7 +1382,6 @@
         float[] spotColor = {0.f, 0.f, 0.f, spotShadowAlpha};
         SurfaceControl.setGlobalShadowSettings(ambientColor, spotColor, lightY, lightZ,
                 lightRadius);
-        setShadowRenderer();
     }
 
     /**
@@ -2669,7 +2655,6 @@
     }
 
     boolean checkCallingPermission(String permission, String func, boolean printLog) {
-        // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == myPid()) {
             return true;
         }
@@ -3109,6 +3094,7 @@
     // Misc IWindowSession methods
     // -------------------------------------------------------------
 
+    /** Freeze the screen during a user-switch event. Called by UserController. */
     @Override
     public void startFreezingScreen(int exitAnim, int enterAnim) {
         if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
@@ -3131,6 +3117,11 @@
         }
     }
 
+    /**
+     * No longer actively demand that the screen remain frozen.
+     * Called by UserController after a user-switch.
+     * This doesn't necessarily immediately unlock the screen; it just allows it if we're ready.
+     */
     @Override
     public void stopFreezingScreen() {
         if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
@@ -3703,12 +3694,33 @@
         }
     }
 
-    @Override
+    /**
+     * Sets the touch mode state.
+     *
+     * To be able to change touch mode state, the caller must either own the focused window, or must
+     * have the MODIFY_TOUCH_MODE_STATE permission.
+     *
+     * @param mode the touch mode to set
+     */
+    @Override // Binder call
     public void setInTouchMode(boolean mode) {
         synchronized (mGlobalLock) {
-            mInTouchMode = mode;
+            if (mInTouchMode == mode) {
+                return;
+            }
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final boolean hasPermission = checkCallingPermission(MODIFY_TOUCH_MODE_STATE,
+                    "setInTouchMode()");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (mInputManager.setInTouchMode(mode, pid, uid, hasPermission)) {
+                    mInTouchMode = mode;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
-        mInputManager.setInTouchMode(mode);
     }
 
     boolean getInTouchMode() {
@@ -3855,14 +3867,20 @@
     }
 
     /**
-     * Generates and returns an up-to-date {@link Bitmap} for the specified taskId. The returned
-     * bitmap will be full size and will not include any secure content.
+     * Generates and returns an up-to-date {@link Bitmap} for the specified taskId.
      *
-     * @param taskId The task ID of the task for which a snapshot is requested.
+     * @param taskId                  The task ID of the task for which a Bitmap is requested.
+     * @param layerCaptureArgsBuilder A {@link SurfaceControl.LayerCaptureArgs.Builder} with
+     *                                arguments for how to capture the Bitmap. The caller can
+     *                                specify any arguments, but this method will ensure that the
+     *                                specified task's SurfaceControl is used and the crop is set to
+     *                                the bounds of that task.
      * @return The Bitmap, or null if no task with the specified ID can be found or the bitmap could
      * not be generated.
      */
-    @Nullable public Bitmap captureTaskBitmap(int taskId) {
+    @Nullable
+    public Bitmap captureTaskBitmap(int taskId,
+            @NonNull SurfaceControl.LayerCaptureArgs.Builder layerCaptureArgsBuilder) {
         if (mTaskSnapshotController.shouldDisableSnapshots()) {
             return null;
         }
@@ -3876,9 +3894,7 @@
             task.getBounds(mTmpRect);
             final SurfaceControl sc = task.getSurfaceControl();
             final SurfaceControl.ScreenshotHardwareBuffer buffer = SurfaceControl.captureLayers(
-                    new SurfaceControl.LayerCaptureArgs.Builder(sc)
-                            .setSourceCrop(mTmpRect)
-                            .build());
+                    layerCaptureArgsBuilder.setLayer(sc).setSourceCrop(mTmpRect).build());
             if (buffer == null) {
                 Slog.w(TAG, "Could not get screenshot buffer for taskId: " + taskId);
                 return null;
@@ -5877,6 +5893,13 @@
             return;
         }
 
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.doStartFreezingDisplay");
+        doStartFreezingDisplay(exitAnim, enterAnim, displayContent, overrideOriginalRotation);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+    }
+
+    private void doStartFreezingDisplay(int exitAnim, int enterAnim, DisplayContent displayContent,
+            int overrideOriginalRotation) {
         ProtoLog.d(WM_DEBUG_ORIENTATION,
                             "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s",
                             exitAnim, enterAnim, Debug.getCallers(8));
@@ -5947,10 +5970,16 @@
             return;
         }
 
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.doStopFreezingDisplayLocked-"
+                + mLastFinishedFreezeSource);
+        doStopFreezingDisplayLocked(displayContent);
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+    }
+
+    private void doStopFreezingDisplayLocked(DisplayContent displayContent) {
         ProtoLog.d(WM_DEBUG_ORIENTATION,
                     "stopFreezingDisplayLocked: Unfreezing now");
 
-
         // We must make a local copy of the displayId as it can be potentially overwritten later on
         // in this method. For example, {@link startFreezingDisplayLocked} may be called as a result
         // of update rotation, but we reference the frozen display after that call in this method.
@@ -7983,27 +8012,29 @@
         @Override
         public boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) {
             return WindowManagerService.this.shouldRestoreImeVisibility(imeTargetWindowToken);
-        }
+       }
 
         @Override
-        public void addTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay) {
+        public void addTrustedTaskOverlay(int taskId,
+                SurfaceControlViewHost.SurfacePackage overlay) {
             synchronized (mGlobalLock) {
                 final Task task = mRoot.getRootTask(taskId);
                 if (task == null) {
                     throw new IllegalArgumentException("no task with taskId" + taskId);
                 }
-                task.addOverlay(overlay);
+                task.addTrustedOverlay(overlay);
             }
         }
 
         @Override
-        public void removeTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay) {
+        public void removeTrustedTaskOverlay(int taskId,
+                SurfaceControlViewHost.SurfacePackage overlay) {
             synchronized (mGlobalLock) {
                 final Task task = mRoot.getRootTask(taskId);
                 if (task == null) {
                     throw new IllegalArgumentException("no task with taskId" + taskId);
                 }
-                task.removeOverlay(overlay);
+                task.removeTrustedOverlay(overlay);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 3ccb06c..ac9fbde 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -821,10 +821,15 @@
     // TODO(b/199277065): Re-assess how app-specific locales are applied based on UXR
     // TODO(b/199277729): Consider whether we need to add special casing for edge cases like
     //  activity-embeddings etc.
-    void updateAppSpecificSettingsForAllActivities(Integer nightMode, LocaleList localesOverride) {
+    void updateAppSpecificSettingsForAllActivitiesInPackage(String packageName, Integer nightMode,
+            LocaleList localesOverride) {
         for (int i = mActivities.size() - 1; i >= 0; --i) {
             final ActivityRecord r = mActivities.get(i);
-            if (r.applyAppSpecificConfig(nightMode, localesOverride) && r.mVisibleRequested) {
+            // Activities from other packages could be sharing this process. Only propagate updates
+            // to those activities that are part of the package whose app-specific settings changed
+            if (packageName.equals(r.packageName)
+                    && r.applyAppSpecificConfig(nightMode, localesOverride)
+                    && r.mVisibleRequested) {
                 r.ensureActivityConfiguration(0 /* globalChanges */, true /* preserveWindow */);
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 79c64b1..0d72e9a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -106,6 +106,7 @@
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
@@ -245,6 +246,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.window.ClientWindowFrames;
+import android.window.IOnBackInvokedCallback;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.KeyInterceptionInfo;
@@ -845,6 +847,11 @@
         }
     };
 
+    /**
+     * @see #setOnBackInvokedCallback(IOnBackInvokedCallback)
+     */
+    private IOnBackInvokedCallback mOnBackInvokedCallback;
+
     @Override
     WindowState asWindowState() {
         return this;
@@ -1061,6 +1068,22 @@
         return true;
     }
 
+    /**
+     * Used by {@link android.window.WindowOnBackInvokedDispatcher} to set the callback to be
+     * called when a back navigation action is initiated.
+     * @see BackNavigationController
+     */
+    void setOnBackInvokedCallback(@Nullable IOnBackInvokedCallback onBackInvokedCallback) {
+        ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "%s: Setting back callback %s",
+                this, onBackInvokedCallback);
+        mOnBackInvokedCallback = onBackInvokedCallback;
+    }
+
+    @Nullable
+    IOnBackInvokedCallback getOnBackInvokedCallback() {
+        return mOnBackInvokedCallback;
+    }
+
     interface PowerManagerWrapper {
         void wakeUp(long time, @WakeReason int reason, String details);
 
@@ -5398,17 +5421,6 @@
             outPoint.offset(-parentBounds.left, -parentBounds.top);
         }
 
-        Task rootTask = getRootTask();
-
-        // If we have root task outsets, that means the top-left
-        // will be outset, and we need to inset ourselves
-        // to account for it. If we actually have shadows we will
-        // then un-inset ourselves by the surfaceInsets.
-        if (rootTask != null) {
-            final int outset = rootTask.getTaskOutset();
-            outPoint.offset(outset, outset);
-        }
-
         // The surface size is larger than the window if the window has positive surface insets.
         transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets);
         outPoint.offset(-mTmpPoint.x, -mTmpPoint.y);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 99abf44..f9de53c 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -44,7 +44,6 @@
         "com_android_server_lights_LightsService.cpp",
         "com_android_server_location_GnssLocationProvider.cpp",
         "com_android_server_locksettings_SyntheticPasswordManager.cpp",
-        "com_android_server_net_NetworkStatsService.cpp",
         "com_android_server_power_PowerManagerService.cpp",
         "com_android_server_powerstats_PowerStatsService.cpp",
         "com_android_server_hint_HintManagerService.cpp",
@@ -71,7 +70,6 @@
         "com_android_server_wm_TaskFpsCallbackController.cpp",
         "onload.cpp",
         ":lib_cachedAppOptimizer_native",
-        ":lib_networkStatsFactory_native",
         ":lib_gameManagerService_native",
     ],
 
@@ -86,7 +84,6 @@
 
     header_libs: [
         "bionic_libc_platform_headers",
-        "bpf_connectivity_headers",
     ],
 }
 
@@ -145,9 +142,6 @@
         "libhidlbase",
         "libutils",
         "libhwui",
-        "libbpf_android",
-        "libnetdutils",
-        "libnetworkstats",
         "libpsi",
         "libdataloader",
         "libincfs",
@@ -214,13 +208,6 @@
 }
 
 filegroup {
-    name: "lib_networkStatsFactory_native",
-    srcs: [
-        "com_android_server_net_NetworkStatsFactory.cpp",
-    ],
-}
-
-filegroup {
     name: "lib_cachedAppOptimizer_native",
     srcs: [
         "com_android_server_am_CachedAppOptimizer.cpp",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 8cb27e1..3c122b0 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -265,7 +265,6 @@
     base::Result<std::unique_ptr<InputChannel>> createInputChannel(JNIEnv* env,
                                                                    const std::string& name);
     base::Result<std::unique_ptr<InputChannel>> createInputMonitor(JNIEnv* env, int32_t displayId,
-                                                                   bool isGestureMonitor,
                                                                    const std::string& name,
                                                                    int32_t pid);
     status_t removeInputChannel(JNIEnv* env, const sp<IBinder>& connectionToken);
@@ -522,11 +521,9 @@
 }
 
 base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputMonitor(
-        JNIEnv* /* env */, int32_t displayId, bool isGestureMonitor, const std::string& name,
-        int32_t pid) {
+        JNIEnv* /* env */, int32_t displayId, const std::string& name, int32_t pid) {
     ATRACE_CALL();
-    return mInputManager->getDispatcher().createInputMonitor(displayId, isGestureMonitor, name,
-                                                             pid);
+    return mInputManager->getDispatcher().createInputMonitor(displayId, name, pid);
 }
 
 status_t NativeInputManager::removeInputChannel(JNIEnv* /* env */,
@@ -1659,7 +1656,7 @@
 }
 
 static jobject nativeCreateInputMonitor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint displayId,
-                                        jboolean isGestureMonitor, jstring nameObj, jint pid) {
+                                        jstring nameObj, jint pid) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     if (displayId == ADISPLAY_ID_NONE) {
@@ -1672,7 +1669,7 @@
     std::string name = nameChars.c_str();
 
     base::Result<std::unique_ptr<InputChannel>> inputChannel =
-            im->createInputMonitor(env, displayId, isGestureMonitor, name, pid);
+            im->createInputMonitor(env, displayId, name, pid);
 
     if (!inputChannel.ok()) {
         std::string message = inputChannel.error().message();
@@ -1707,7 +1704,6 @@
     im->pilferPointers(token);
 }
 
-
 static void nativeSetInputFilterEnabled(JNIEnv* /* env */, jclass /* clazz */,
         jlong ptr, jboolean enabled) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1715,11 +1711,13 @@
     im->getInputManager()->getDispatcher().setInputFilterEnabled(enabled);
 }
 
-static void nativeSetInTouchMode(JNIEnv* /* env */, jclass /* clazz */,
-        jlong ptr, jboolean inTouchMode) {
+static jboolean nativeSetInTouchMode(JNIEnv* /* env */, jclass /* clazz */, jlong ptr,
+                                     jboolean inTouchMode, jint pid, jint uid,
+                                     jboolean hasPermission) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
-    im->getInputManager()->getDispatcher().setInTouchMode(inTouchMode);
+    return im->getInputManager()->getDispatcher().setInTouchMode(inTouchMode, pid, uid,
+                                                                 hasPermission);
 }
 
 static void nativeSetMaximumObscuringOpacityForTouch(JNIEnv* /* env */, jclass /* clazz */,
@@ -2381,12 +2379,12 @@
         {"nativeGetKeyCodeForKeyLocation", "(JII)I", (void*)nativeGetKeyCodeForKeyLocation},
         {"nativeCreateInputChannel", "(JLjava/lang/String;)Landroid/view/InputChannel;",
          (void*)nativeCreateInputChannel},
-        {"nativeCreateInputMonitor", "(JIZLjava/lang/String;I)Landroid/view/InputChannel;",
+        {"nativeCreateInputMonitor", "(JILjava/lang/String;I)Landroid/view/InputChannel;",
          (void*)nativeCreateInputMonitor},
         {"nativeRemoveInputChannel", "(JLandroid/os/IBinder;)V", (void*)nativeRemoveInputChannel},
         {"nativePilferPointers", "(JLandroid/os/IBinder;)V", (void*)nativePilferPointers},
         {"nativeSetInputFilterEnabled", "(JZ)V", (void*)nativeSetInputFilterEnabled},
-        {"nativeSetInTouchMode", "(JZ)V", (void*)nativeSetInTouchMode},
+        {"nativeSetInTouchMode", "(JZIIZ)Z", (void*)nativeSetInTouchMode},
         {"nativeSetMaximumObscuringOpacityForTouch", "(JF)V",
          (void*)nativeSetMaximumObscuringOpacityForTouch},
         {"nativeSetBlockUntrustedTouchesMode", "(JI)V", (void*)nativeSetBlockUntrustedTouchesMode},
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 166a0f5..0584604 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -509,7 +509,7 @@
 template <class T_list, class T_sv_info>
 Return<void> GnssCallback::gnssSvStatusCbImpl(const T_list& svStatus) {
     // In HIDL or AIDL v1, if no listener is registered, do not report svInfoList to the framework.
-    if (gnssHalAidl == nullptr || gnssHalAidl->getInterfaceVersion() == 1) {
+    if (gnssHalAidl == nullptr || gnssHalAidl->getInterfaceVersion() <= 1) {
         if (!isSvStatusRegistered) {
             return Void();
         }
@@ -695,7 +695,7 @@
 
 Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
     // In AIDL v1, if no listener is registered, do not report nmea to the framework.
-    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() == 1) {
+    if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() <= 1) {
         if (!isNmeaRegistered) {
             return Status::ok();
         }
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index ba5b3f5..1c6a3b5 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -51,8 +51,6 @@
 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
 int register_android_server_SyntheticPasswordManager(JNIEnv* env);
 int register_android_hardware_display_DisplayViewport(JNIEnv* env);
-int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
-int register_android_server_net_NetworkStatsService(JNIEnv* env);
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env);
 int register_android_server_am_LowMemDetector(JNIEnv* env);
 int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(JNIEnv* env);
@@ -110,8 +108,6 @@
     register_android_server_SyntheticPasswordManager(env);
     register_android_graphics_GraphicsStatsService(env);
     register_android_hardware_display_DisplayViewport(env);
-    register_android_server_net_NetworkStatsFactory(env);
-    register_android_server_net_NetworkStatsService(env);
     register_android_server_am_CachedAppOptimizer(env);
     register_android_server_am_LowMemDetector(env);
     register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(env);
diff --git a/services/core/lint-baseline.xml b/services/core/lint-baseline.xml
index c5b0549..69e13b3 100644
--- a/services/core/lint-baseline.xml
+++ b/services/core/lint-baseline.xml
@@ -1,158 +1,140 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+<issues format="5" by="lint 7.2.0-dev">
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="            return Settings.Secure.getInt(context.getContentResolver(),"
-        errorLine2="                   ~~~~~~">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/biometrics/BiometricService.java"
-            line="1106"
-            column="20"/>
+            line="1122"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="            return Settings.Secure.getInt(context.getContentResolver(),"
-        errorLine2="                   ~~~~~~">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/biometrics/BiometricService.java"
-            line="1111"
-            column="20"/>
+            line="1127"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "
-        errorLine1="            return Settings.Secure.getString(mContentResolver, mKey);"
-        errorLine2="                                   ~~~~~~~~~">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
+        <location
+            file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java"
+            line="670"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. ">
+        <location
+            file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java"
+            line="678"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. ">
+        <location
+            file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java"
+            line="679"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. ">
+        <location
+            file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java"
+            line="696"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. ">
+        <location
+            file="packages/modules/Bluetooth/service/java/com/android/server/bluetooth/BluetoothManagerService.java"
+            line="705"/>
+    </issue>
+
+    <issue
+        id="NonUserGetterCalled"
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/CertBlacklister.java"
-            line="73"
-            column="36"/>
+            line="73"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="        }"
-        errorLine2="      ^">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/clipboard/ClipboardService.java"
-            line="973"
-            column="7"/>
+            line="1072"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="            boolean accessibilityEnabled = Settings.Secure.getInt(cr,"
-        errorLine2="                                                           ~~~~~~">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/DockObserver.java"
-            line="176"
-            column="60"/>
+            line="260"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "
-        errorLine1="            String mediaButtonReceiverInfo = Settings.Secure.getString(mContentResolver,"
-        errorLine2="                                             ~~~~~~~~~">
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/media/MediaSessionService.java"
-            line="928"
-            column="46"/>
+            line="928"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="            final boolean isSecureFrpEnabled ="
-        errorLine2="                                   ~~~~~~">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java"
-            line="1959"
-            column="36"/>
+            line="1902"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="    private int getUnknownSourcesSettings() {"
-        errorLine2="                                      ~~~~~~">
-        <location
-            file="frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java"
-            line="16741"
-            column="39"/>
-    </issue>
-
-    <issue
-        id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "
-        errorLine1="            String inputMethodComponent = Settings.Secure.getString(mContext.getContentResolver(),"
-        errorLine2="                                  ~~~~~~~~~">
-        <location
-            file="frameworks/base/services/core/java/com/android/server/SensorPrivacyService.java"
-            line="489"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. "
-        errorLine1="            return Settings.Secure.getString(getContentResolverAsUser(userId), key);"
-        errorLine2="           ~~~~~~~~~">
+        message="`android.provider.Settings.Secure#getString()` called from system process. Please call `android.provider.Settings.Secure#getStringForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java"
-            line="1994"
-            column="12"/>
+            line="2069"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="            return Settings.Secure.getInt(getContentResolverAsUser(userId), key, def);"
-        errorLine2="           ~~~~~~">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java"
-            line="2001"
-            column="12"/>
+            line="2076"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="                        if (Settings.Secure.getInt(mContext.getContentResolver(),"
-        errorLine2="                                            ~~~~~~">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java"
-            line="980"
-            column="45"/>
+            line="984"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="                &amp;&amp; Settings.Secure.getInt(mContext.getContentResolver(),"
-        errorLine2="                                   ~~~~~~">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java"
-            line="1442"
-            column="36"/>
+            line="1446"/>
     </issue>
 
     <issue
         id="NonUserGetterCalled"
-        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. "
-        errorLine1="                &amp;&amp; Settings.Secure.getInt(mContext.getContentResolver(),"
-        errorLine2="                                   ~~~~~~">
+        message="`android.provider.Settings.Secure#getInt()` called from system process. Please call `android.provider.Settings.Secure#getIntForUser()` instead. ">
         <location
             file="frameworks/base/services/core/java/com/android/server/notification/ZenModeHelper.java"
-            line="1444"
-            column="36"/>
+            line="1448"/>
     </issue>
 
 </issues>
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 79d8036..be0ddc1 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -123,6 +123,18 @@
                 <xs:annotation name="nonnull"/>
                 <xs:annotation name="final"/>
             </xs:element>
+            <!-- The minimum HDR video size at which high-brightness-mode is allowed to operate.
+                Default is 0.5 if not specified-->
+            <xs:element name="minimumHdrPercentOfScreen" type="nonNegativeDecimal"
+                        minOccurs="0" maxOccurs="1">
+                <xs:annotation name="nullable"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+            <!-- This LUT specifies how to boost HDR brightness at given SDR brightness (nits). -->
+            <xs:element type="sdrHdrRatioMap" name="sdrHdrRatioMap" minOccurs="0" maxOccurs="1">
+                <xs:annotation name="nullable"/>
+                <xs:annotation name="final"/>
+            </xs:element>
         </xs:all>
         <xs:attribute name="enabled" type="xs:boolean" use="optional"/>
     </xs:complexType>
@@ -158,6 +170,14 @@
         </xs:restriction>
     </xs:simpleType>
 
+    <!-- Maps to DisplayDeviceConfig.INTERPOLATION_* values. -->
+    <xs:simpleType name="interpolation">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="default"/>
+            <xs:enumeration value="linear"/>
+        </xs:restriction>
+    </xs:simpleType>
+
     <xs:complexType name="thermalThrottling">
         <xs:complexType>
             <xs:element type="brightnessThrottlingMap" name="brightnessThrottlingMap">
@@ -196,6 +216,7 @@
                 <xs:annotation name="final"/>
             </xs:element>
         </xs:sequence>
+        <xs:attribute name="interpolation" type="interpolation" use="optional"/>
     </xs:complexType>
 
     <xs:complexType name="point">
@@ -211,6 +232,28 @@
         </xs:sequence>
     </xs:complexType>
 
+    <xs:complexType name="sdrHdrRatioMap">
+        <xs:sequence>
+            <xs:element name="point" type="sdrHdrRatioPoint" maxOccurs="unbounded" minOccurs="2">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="sdrHdrRatioPoint">
+        <xs:sequence>
+            <xs:element type="nonNegativeDecimal" name="sdrNits">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+            <xs:element type="nonNegativeDecimal" name="hdrRatio">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
     <xs:simpleType name="nonNegativeDecimal">
         <xs:restriction base="xs:decimal">
             <xs:minInclusive value="0.0"/>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 0b7df4d..2890d68 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -90,23 +90,35 @@
     ctor public HighBrightnessMode();
     method @NonNull public final boolean getAllowInLowPowerMode_all();
     method public boolean getEnabled();
+    method @Nullable public final java.math.BigDecimal getMinimumHdrPercentOfScreen_all();
     method @NonNull public final java.math.BigDecimal getMinimumLux_all();
     method @Nullable public final com.android.server.display.config.RefreshRateRange getRefreshRate_all();
+    method @Nullable public final com.android.server.display.config.SdrHdrRatioMap getSdrHdrRatioMap_all();
     method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatusLimit_all();
     method public com.android.server.display.config.HbmTiming getTiming_all();
     method @NonNull public final java.math.BigDecimal getTransitionPoint_all();
     method public final void setAllowInLowPowerMode_all(@NonNull boolean);
     method public void setEnabled(boolean);
+    method public final void setMinimumHdrPercentOfScreen_all(@Nullable java.math.BigDecimal);
     method public final void setMinimumLux_all(@NonNull java.math.BigDecimal);
     method public final void setRefreshRate_all(@Nullable com.android.server.display.config.RefreshRateRange);
+    method public final void setSdrHdrRatioMap_all(@Nullable com.android.server.display.config.SdrHdrRatioMap);
     method public final void setThermalStatusLimit_all(@NonNull com.android.server.display.config.ThermalStatus);
     method public void setTiming_all(com.android.server.display.config.HbmTiming);
     method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal);
   }
 
+  public enum Interpolation {
+    method public String getRawName();
+    enum_constant public static final com.android.server.display.config.Interpolation _default;
+    enum_constant public static final com.android.server.display.config.Interpolation linear;
+  }
+
   public class NitsMap {
     ctor public NitsMap();
+    method public com.android.server.display.config.Interpolation getInterpolation();
     method @NonNull public final java.util.List<com.android.server.display.config.Point> getPoint();
+    method public void setInterpolation(com.android.server.display.config.Interpolation);
   }
 
   public class Point {
@@ -125,6 +137,19 @@
     method public final void setMinimum(java.math.BigInteger);
   }
 
+  public class SdrHdrRatioMap {
+    ctor public SdrHdrRatioMap();
+    method @NonNull public final java.util.List<com.android.server.display.config.SdrHdrRatioPoint> getPoint();
+  }
+
+  public class SdrHdrRatioPoint {
+    ctor public SdrHdrRatioPoint();
+    method @NonNull public final java.math.BigDecimal getHdrRatio();
+    method @NonNull public final java.math.BigDecimal getSdrNits();
+    method public final void setHdrRatio(@NonNull java.math.BigDecimal);
+    method public final void setSdrNits(@NonNull java.math.BigDecimal);
+  }
+
   public class SensorDetails {
     ctor public SensorDetails();
     method @Nullable public final String getName();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e99b1f9..921e2e1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -134,6 +134,7 @@
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
+import static android.provider.Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.provider.Telephony.Carriers.DPC_URI;
 import static android.provider.Telephony.Carriers.ENFORCE_KEY;
@@ -214,6 +215,7 @@
 import android.app.admin.UnsafeStateException;
 import android.app.backup.IBackupManager;
 import android.app.compat.CompatChanges;
+import android.app.role.RoleManager;
 import android.app.trust.TrustManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.compat.annotation.ChangeId;
@@ -222,6 +224,7 @@
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.IIntentReceiver;
@@ -6847,7 +6850,7 @@
                 String.format(NOT_SYSTEM_CALLER_MSG, "call isAlwaysOnVpnLockdownEnabledForUser"));
         synchronized (getLockObject()) {
             ActiveAdmin admin = getDeviceOrProfileOwnerAdminLocked(userHandle);
-            return admin != null ? admin.mAlwaysOnVpnLockdown : null;
+            return admin != null && admin.mAlwaysOnVpnLockdown;
         }
     }
 
@@ -10855,6 +10858,8 @@
         final int userHandle = user.getIdentifier();
         final long id = mInjector.binderClearCallingIdentity();
         try {
+            maybeInstallDeviceManagerRoleHolderInUser(userHandle);
+
             manageUserUnchecked(admin, profileOwner, userHandle, adminExtras,
                     /* showDisclaimer= */ true);
 
@@ -11613,6 +11618,7 @@
 
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+                || isFinancedDeviceOwner(caller)
                 || isProfileOwner(caller)
                 || (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
 
@@ -13988,7 +13994,7 @@
 
         synchronized (getLockObject()) {
             if (isFinancedDeviceOwner(caller)) {
-                enforceCanSetPermissionGrantOnFinancedDevice(packageName, permission);
+                enforcePermissionGrantStateOnFinancedDevice(packageName, permission);
             }
             long ident = mInjector.binderClearCallingIdentity();
             try {
@@ -14049,14 +14055,14 @@
         }
     }
 
-    private void enforceCanSetPermissionGrantOnFinancedDevice(
+    private void enforcePermissionGrantStateOnFinancedDevice(
             String packageName, String permission) {
         if (!Manifest.permission.READ_PHONE_STATE.equals(permission)) {
-            throw new SecurityException("Cannot grant " + permission
-                    + " when managing a financed device");
+            throw new SecurityException(permission + " cannot be used when managing a financed"
+                    + " device for permission grant state");
         } else if (!mOwners.getDeviceOwnerPackageName().equals(packageName)) {
-            throw new SecurityException("Cannot grant permission to a package that is not"
-                    + " the device owner");
+            throw new SecurityException("Device owner package is the only package that can be used"
+                    + " for permission grant state when managing a financed device");
         }
     }
 
@@ -14065,10 +14071,14 @@
             String packageName, String permission) throws RemoteException {
         final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
         Preconditions.checkCallAuthorization(isSystemUid(caller) || (caller.hasAdminComponent()
-                && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+                && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)
+                || isFinancedDeviceOwner(caller)))
                 || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
 
         synchronized (getLockObject()) {
+            if (isFinancedDeviceOwner(caller)) {
+                enforcePermissionGrantStateOnFinancedDevice(packageName, permission);
+            }
             return mInjector.binderWithCleanCallingIdentity(() -> {
                 int granted;
                 if (getTargetSdk(caller.getPackageName(), caller.getUserId())
@@ -17689,6 +17699,9 @@
             }
 
             final long startTime = SystemClock.elapsedRealtime();
+
+            onCreateAndProvisionManagedProfileStarted(provisioningParams);
+
             final Set<String> nonRequiredApps = provisioningParams.isLeaveAllSystemAppsEnabled()
                     ? Collections.emptySet()
                     : mOverlayPackagesProvider.getNonRequiredApps(
@@ -17700,6 +17713,7 @@
                     Slogf.i(LOG_TAG, "Disallowed package [" + packageName + "]");
                 }
             }
+
             userInfo = mUserManager.createProfileForUserEvenWhenDisallowed(
                     provisioningParams.getProfileName(),
                     UserManager.USER_TYPE_PROFILE_MANAGED,
@@ -17718,7 +17732,7 @@
                     startTime,
                     callerPackage);
 
-            onCreateAndProvisionManagedProfileStarted(provisioningParams);
+            maybeInstallDeviceManagerRoleHolderInUser(userInfo.id);
 
             installExistingAdminPackage(userInfo.id, admin.getPackageName());
             if (!enableAdminAndSetProfileOwner(
@@ -17786,6 +17800,43 @@
     private void onCreateAndProvisionManagedProfileCompleted(
             ManagedProfileProvisioningParams provisioningParams) {}
 
+    private void maybeInstallDeviceManagerRoleHolderInUser(int targetUserId) {
+        String deviceManagerRoleHolderPackageName = getDeviceManagerRoleHolderPackageName(mContext);
+        if (deviceManagerRoleHolderPackageName == null) {
+            Slogf.d(LOG_TAG, "No device manager role holder specified.");
+            return;
+        }
+        try {
+            if (mIPackageManager.isPackageAvailable(
+                    deviceManagerRoleHolderPackageName, targetUserId)) {
+                Slogf.d(LOG_TAG, "The device manager role holder "
+                        + deviceManagerRoleHolderPackageName + " is already installed in "
+                        + "user " + targetUserId);
+                return;
+            }
+            Slogf.d(LOG_TAG, "Installing the device manager role holder "
+                    + deviceManagerRoleHolderPackageName + " in user " + targetUserId);
+            mIPackageManager.installExistingPackageAsUser(
+                    deviceManagerRoleHolderPackageName,
+                    targetUserId,
+                    PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+                    PackageManager.INSTALL_REASON_POLICY,
+                    /* whiteListedPermissions= */ null);
+        } catch (RemoteException e) {
+            // Does not happen, same process
+        }
+    }
+
+    private String getDeviceManagerRoleHolderPackageName(Context context) {
+        RoleManager roleManager = context.getSystemService(RoleManager.class);
+        List<String> roleHolders =
+                roleManager.getRoleHolders(RoleManager.ROLE_DEVICE_MANAGER);
+        if (roleHolders.isEmpty()) {
+            return null;
+        }
+        return roleHolders.get(0);
+    }
+
     private void resetInteractAcrossProfilesAppOps() {
         mInjector.getCrossProfileApps().clearInteractAcrossProfilesAppOps();
         pregrantDefaultInteractAcrossProfilesAppOps();
@@ -18669,4 +18720,26 @@
             mContext.sendBroadcastAsUser(intent, user);
         }
     }
+
+    public boolean isDpcDownloaded() {
+        Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+        ContentResolver cr = mContext.getContentResolver();
+
+        return mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.getIntForUser(
+                cr, MANAGED_PROVISIONING_DPC_DOWNLOADED,
+                /* def= */ 0, /* userHandle= */ cr.getUserId())
+                == 1);
+    }
+
+    public void setDpcDownloaded(boolean downloaded) {
+        Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+        int setTo = downloaded ? 1 : 0;
+
+        mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.putInt(
+                mContext.getContentResolver(), MANAGED_PROVISIONING_DPC_DOWNLOADED, setTo));
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 6bc7ba6..f0ceb31 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -184,7 +184,7 @@
             Files.write(file.toPath(), versionBytes);
             versionFile.commit();
         } catch (IOException e) {
-            Slog.e(LOG_TAG, String.format("Writing version %d failed: %s", version), e);
+            Slog.e(LOG_TAG, String.format("Writing version %d failed", version), e);
             versionFile.rollback();
         }
     }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d0c861f..a7539b5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -54,7 +54,6 @@
 import android.net.ConnectivityManager;
 import android.net.ConnectivityModuleConnector;
 import android.net.NetworkStackClient;
-import android.net.TrafficStats;
 import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Build;
@@ -85,6 +84,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
+import android.util.Dumpable;
 import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.Pair;
@@ -143,7 +143,6 @@
 import com.android.server.media.metrics.MediaMetricsManagerService;
 import com.android.server.media.projection.MediaProjectionManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
-import com.android.server.net.NetworkStatsService;
 import com.android.server.net.watchlist.NetworkWatchlistService;
 import com.android.server.notification.NotificationManagerService;
 import com.android.server.oemlock.OemLockService;
@@ -154,6 +153,7 @@
 import com.android.server.os.SchedulingPolicyService;
 import com.android.server.people.PeopleService;
 import com.android.server.pm.ApexManager;
+import com.android.server.pm.ApexSystemServiceInfo;
 import com.android.server.pm.CrossProfileAppsService;
 import com.android.server.pm.DataLoaderManagerService;
 import com.android.server.pm.DynamicCodeLoggingService;
@@ -224,8 +224,8 @@
 import java.util.Arrays;
 import java.util.Date;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Timer;
 import java.util.TreeSet;
 import java.util.concurrent.CountDownLatch;
@@ -396,6 +396,8 @@
             "com.android.server.media.MediaResourceMonitorService";
     private static final String CONNECTIVITY_SERVICE_INITIALIZER_CLASS =
             "com.android.server.ConnectivityServiceInitializer";
+    private static final String NETWORK_STATS_SERVICE_INITIALIZER_CLASS =
+            "com.android.server.NetworkStatsServiceInitializer";
     private static final String IP_CONNECTIVITY_METRICS_CLASS =
             "com.android.server.connectivity.IpConnectivityMetrics";
     private static final String MEDIA_COMMUNICATION_SERVICE_CLASS =
@@ -662,7 +664,12 @@
     }
 
     @Override
-    public void dump(IndentingPrintWriter pw, String[] args) {
+    public String getDumpableName() {
+        return SystemServer.class.getSimpleName();
+    }
+
+    @Override
+    public void dump(PrintWriter pw, String[] args) {
         pw.printf("Runtime restart: %b\n", mRuntimeRestart);
         pw.printf("Start count: %d\n", mStartCount);
         pw.print("Runtime start-up time: ");
@@ -1392,10 +1399,8 @@
         DynamicSystemService dynamicSystem = null;
         IStorageManager storageManager = null;
         NetworkManagementService networkManagement = null;
-        IpSecService ipSecService = null;
         VpnManagerService vpnManager = null;
         VcnManagementService vcnManagement = null;
-        NetworkStatsService networkStats = null;
         NetworkPolicyManagerService networkPolicy = null;
         WindowManagerService wm = null;
         SerialService serial = null;
@@ -1472,7 +1477,7 @@
             // TelecomLoader hooks into classes with defined HFP logic,
             // so check for either telephony or microphone.
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE) ||
-                mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
                 t.traceBegin("StartTelecomLoaderService");
                 mSystemServiceManager.startService(TelecomLoaderService.class);
                 t.traceEnd();
@@ -1480,7 +1485,7 @@
 
             t.traceBegin("StartTelephonyRegistry");
             telephonyRegistry = new TelephonyRegistry(
-                context, new TelephonyRegistry.ConfigurationProvider());
+                    context, new TelephonyRegistry.ConfigurationProvider());
             ServiceManager.addService("telephony.registry", telephonyRegistry);
             t.traceEnd();
 
@@ -1505,6 +1510,10 @@
             SQLiteCompatibilityWalFlags.reset();
             t.traceEnd();
 
+            t.traceBegin("UpdateWatchdogTimeout");
+            Watchdog.getInstance().registerSettingsObserver(context);
+            t.traceEnd();
+
             // Records errors and logs, for example wtf()
             // Currently this service indirectly depends on SettingsProvider so do this after
             // InstallSystemProviders.
@@ -1897,15 +1906,6 @@
             }
             t.traceEnd();
 
-            t.traceBegin("StartIpSecService");
-            try {
-                ipSecService = IpSecService.create(context);
-                ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
-            } catch (Throwable e) {
-                reportWtf("starting IpSec Service", e);
-            }
-            t.traceEnd();
-
             t.traceBegin("StartFontManagerService");
             mSystemServiceManager.startService(new FontManagerService.Lifecycle(context, safeMode));
             t.traceEnd();
@@ -1926,13 +1926,10 @@
             t.traceEnd();
 
             t.traceBegin("StartNetworkStatsService");
-            try {
-                networkStats = NetworkStatsService.create(context);
-                ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
-                TrafficStats.init(context);
-            } catch (Throwable e) {
-                reportWtf("starting NetworkStats Service", e);
-            }
+            // This has to be called before NetworkPolicyManager because NetworkPolicyManager
+            // needs to take NetworkStatsService to initialize.
+            mSystemServiceManager.startServiceFromJar(NETWORK_STATS_SERVICE_INITIALIZER_CLASS,
+                    CONNECTIVITY_SERVICE_APEX_PATH);
             t.traceEnd();
 
             t.traceBegin("StartNetworkPolicyManagerService");
@@ -2784,7 +2781,6 @@
 
         // These are needed to propagate to the runnable below.
         final NetworkManagementService networkManagementF = networkManagement;
-        final NetworkStatsService networkStatsF = networkStats;
         final NetworkPolicyManagerService networkPolicyF = networkPolicy;
         final CountryDetectorService countryDetectorF = countryDetector;
         final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
@@ -2792,7 +2788,6 @@
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final MediaRouterService mediaRouterF = mediaRouter;
         final MmsServiceBroker mmsServiceF = mmsService;
-        final IpSecService ipSecServiceF = ipSecService;
         final VpnManagerService vpnManagerF = vpnManager;
         final VcnManagementService vcnManagementF = vcnManagement;
         final WindowManagerService windowManagerF = wm;
@@ -2884,24 +2879,6 @@
                         .networkScoreAndNetworkManagementServiceReady();
             }
             t.traceEnd();
-            t.traceBegin("MakeIpSecServiceReady");
-            try {
-                if (ipSecServiceF != null) {
-                    ipSecServiceF.systemReady();
-                }
-            } catch (Throwable e) {
-                reportWtf("making IpSec Service ready", e);
-            }
-            t.traceEnd();
-            t.traceBegin("MakeNetworkStatsServiceReady");
-            try {
-                if (networkStatsF != null) {
-                    networkStatsF.systemReady();
-                }
-            } catch (Throwable e) {
-                reportWtf("making Network Stats Service ready", e);
-            }
-            t.traceEnd();
             t.traceBegin("MakeConnectivityServiceReady");
             try {
                 if (connectivityF != null) {
@@ -3017,7 +2994,9 @@
             t.traceEnd();
             t.traceBegin("MakeTelephonyRegistryReady");
             try {
-                if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
+                if (telephonyRegistryF != null) {
+                    telephonyRegistryF.systemRunning();
+                }
             } catch (Throwable e) {
                 reportWtf("Notifying TelephonyRegistry running", e);
             }
@@ -3082,10 +3061,12 @@
      */
     private void startApexServices(@NonNull TimingsTraceAndSlog t) {
         t.traceBegin("startApexServices");
-        Map<String, String> services = ApexManager.getInstance().getApexSystemServices();
-        // TODO(satayev): introduce android:order for services coming the same apexes
-        for (String name : new TreeSet<>(services.keySet())) {
-            String jarPath = services.get(name);
+        // TODO(b/192880996): get the list from "android" package, once the manifest entries
+        // are migrated to system manifest.
+        List<ApexSystemServiceInfo> services = ApexManager.getInstance().getApexSystemServices();
+        for (ApexSystemServiceInfo info : services) {
+            String name = info.getName();
+            String jarPath = info.getJarPath();
             t.traceBegin("starting " + name);
             if (TextUtils.isEmpty(jarPath)) {
                 mSystemServiceManager.startService(name);
@@ -3186,11 +3167,6 @@
     }
 
     private void startAmbientContextService(@NonNull TimingsTraceAndSlog t) {
-        if (!AmbientContextManagerService.isDetectionServiceConfigured()) {
-            Slog.d(TAG, "AmbientContextDetectionService is not configured on this device");
-            return;
-        }
-
         t.traceBegin("StartAmbientContextService");
         mSystemServiceManager.startService(AmbientContextManagerService.class);
         t.traceEnd();
diff --git a/services/people/java/com/android/server/people/data/EventIndex.java b/services/people/java/com/android/server/people/data/EventIndex.java
index 6a13b0e..02afb8d 100644
--- a/services/people/java/com/android/server/people/data/EventIndex.java
+++ b/services/people/java/com/android/server/people/data/EventIndex.java
@@ -254,7 +254,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mLastUpdatedTime, mEventBitmaps);
+        return Objects.hash(mLastUpdatedTime, Arrays.hashCode(mEventBitmaps));
     }
 
     synchronized void writeToProto(@NonNull ProtoOutputStream protoOutputStream) {
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 9e83f8e..ca9ff6f 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -2727,7 +2727,7 @@
         // The second line will throw NPE because it will call lambda 1 with null, since argThat()
         // returns null. So we guard against that by checking for null.
         return packageInfo ->
-                packageInfo != null && packageInfo.packageName.equals(packageInfo.packageName);
+                packageInfo != null && packageInfo.packageName.equals(packageData.packageName);
     }
 
     /** Matches {@link ApplicationInfo} whose package name is {@code packageData.packageName}. */
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp b/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
index 16d6241..0a9b7b1 100644
--- a/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
@@ -32,7 +32,7 @@
     name: "test_com.android.server",
     manifest: "manifest.json",
     androidManifest: "AndroidManifest.xml",
-    java_libs: ["FakeApexSystemService"],
+    java_libs: ["FakeApexSystemServices"],
     file_contexts: ":apex.test-file_contexts",
     key: "test_com.android.server.key",
     updatable: false,
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml b/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml
index eb741ca..6bec284 100644
--- a/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml
@@ -21,21 +21,29 @@
     <application android:hasCode="false" android:testOnly="true">
         <apex-system-service
             android:name="com.android.server.testing.FakeApexSystemService"
-            android:path="/apex/test_com.android.server/javalib/FakeApexSystemService.jar"
-            android:minSdkVersion="30"/>
+            android:path="/apex/test_com.android.server/javalib/FakeApexSystemServices.jar"
+            android:minSdkVersion="30"
+        />
+
+        <apex-system-service
+            android:name="com.android.server.testing.FakeApexSystemService2"
+            android:path="/apex/test_com.android.server/javalib/FakeApexSystemServices.jar"
+            android:minSdkVersion="30"
+            android:initOrder="1"
+        />
 
         <!-- Always inactive system service, since maxSdkVersion is low -->
         <apex-system-service
-            android:name="com.android.apex.test.OldApexSystemService"
-            android:path="/apex/com.android.apex.test/javalib/fake.jar"
+            android:name="com.android.server.testing.OldApexSystemService"
+            android:path="/apex/test_com.android.server/javalib/fake.jar"
             android:minSdkVersion="1"
             android:maxSdkVersion="1"
         />
 
         <!-- Always inactive system service, since minSdkVersion is high -->
         <apex-system-service
-            android:name="com.android.apex.test.NewApexSystemService"
-            android:path="/apex/com.android.apex.test/javalib/fake.jar"
+            android:name="com.android.server.testing.NewApexSystemService"
+            android:path="/apex/test_com.android.server/javalib/fake.jar"
             android:minSdkVersion="999999"
         />
     </application>
diff --git a/services/tests/apexsystemservices/service/Android.bp b/services/tests/apexsystemservices/services/Android.bp
similarity index 94%
rename from services/tests/apexsystemservices/service/Android.bp
rename to services/tests/apexsystemservices/services/Android.bp
index 9d04f39..477ea4c 100644
--- a/services/tests/apexsystemservices/service/Android.bp
+++ b/services/tests/apexsystemservices/services/Android.bp
@@ -8,7 +8,7 @@
 }
 
 java_library {
-    name: "FakeApexSystemService",
+    name: "FakeApexSystemServices",
     srcs: ["**/*.java"],
     sdk_version: "system_server_current",
     libs: [
diff --git a/services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java b/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService.java
similarity index 100%
rename from services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java
rename to services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService.java
diff --git a/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java b/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java
new file mode 100644
index 0000000..e83343b
--- /dev/null
+++ b/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java
@@ -0,0 +1,41 @@
+/*
+ * 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.testing;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.server.SystemService;
+
+/**
+ * A fake system service that just logs when it is started.
+ */
+public class FakeApexSystemService2 extends SystemService {
+
+    private static final String TAG = "FakeApexSystemService";
+
+    public FakeApexSystemService2(@NonNull Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        Log.d(TAG, "FakeApexSystemService2 onStart");
+    }
+}
diff --git a/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
index 2b453a9..10635a1 100644
--- a/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
+++ b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
@@ -37,9 +37,15 @@
 import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 
+import java.util.Objects;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class ApexSystemServicesTestCases extends BaseHostJUnit4Test {
 
+    private static final int REBOOT_TIMEOUT = 1 * 60 * 1000;
+
     private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
     private final TemporaryFolder mTemporaryFolder = new TemporaryFolder();
     private final SystemPreparer mPreparer = new SystemPreparer(mTemporaryFolder, this::getDevice);
@@ -67,7 +73,7 @@
     }
 
     @Test
-    public void noApexSystemServerStartsWithoutApex() throws Exception {
+    public void testNoApexSystemServiceStartsWithoutApex() throws Exception {
         mPreparer.reboot();
 
         assertThat(getFakeApexSystemServiceLogcat())
@@ -75,20 +81,55 @@
     }
 
     @Test
-    public void apexSystemServerStarts() throws Exception {
+    public void testApexSystemServiceStarts() throws Exception {
         // Pre-install the apex
         String apex = "test_com.android.server.apex";
         mPreparer.pushResourceFile(apex, "/system/apex/" + apex);
         // Reboot activates the apex
         mPreparer.reboot();
 
+        mDevice.waitForBootComplete(REBOOT_TIMEOUT);
+
         assertThat(getFakeApexSystemServiceLogcat())
                 .contains("FakeApexSystemService onStart");
     }
 
+    @Test
+    public void testInitOrder() throws Exception {
+        // Pre-install the apex
+        String apex = "test_com.android.server.apex";
+        mPreparer.pushResourceFile(apex, "/system/apex/" + apex);
+        // Reboot activates the apex
+        mPreparer.reboot();
+
+        mDevice.waitForBootComplete(REBOOT_TIMEOUT);
+
+        assertThat(getFakeApexSystemServiceLogcat().lines()
+                .map(ApexSystemServicesTestCases::getDebugMessage)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList()))
+                .containsExactly(
+                        // Second service has a higher initOrder and must be started first
+                        "FakeApexSystemService2 onStart",
+                        "FakeApexSystemService onStart"
+                )
+                .inOrder();
+    }
+
     private String getFakeApexSystemServiceLogcat() throws DeviceNotAvailableException {
         return mDevice.executeAdbCommand("logcat", "-v", "brief", "-d", "FakeApexSystemService:D",
                 "*:S");
     }
 
+    private static final Pattern DEBUG_MESSAGE =
+            Pattern.compile("(FakeApexSystemService[0-9]* onStart)");
+
+    private static String getDebugMessage(String logcatLine) {
+        return DEBUG_MESSAGE.matcher(logcatLine)
+                .results()
+                .map(m -> m.group(1))
+                .findFirst()
+                .orElse(null);
+    }
+
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index 08de62b..ed232e5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -60,6 +60,7 @@
 import android.service.games.IGameSession;
 import android.service.games.IGameSessionController;
 import android.service.games.IGameSessionService;
+import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost.SurfacePackage;
 
 import androidx.test.filters.SmallTest;
@@ -405,7 +406,7 @@
         mFakeGameSessionService.removePendingFutureForTaskId(10)
                 .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
 
-        verify(mMockWindowManagerInternal).addTaskOverlay(eq(10), eq(mockSurfacePackage10));
+        verify(mMockWindowManagerInternal).addTrustedTaskOverlay(eq(10), eq(mockSurfacePackage10));
     }
 
     @Test
@@ -555,8 +556,9 @@
 
         stopTask(10);
 
-        verify(mMockWindowManagerInternal).addTaskOverlay(eq(10), eq(mockSurfacePackage10));
-        verify(mMockWindowManagerInternal).removeTaskOverlay(eq(10), eq(mockSurfacePackage10));
+        verify(mMockWindowManagerInternal).addTrustedTaskOverlay(eq(10), eq(mockSurfacePackage10));
+        verify(mMockWindowManagerInternal).removeTrustedTaskOverlay(eq(10),
+                eq(mockSurfacePackage10));
     }
 
     @Test
@@ -746,6 +748,11 @@
         mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockOverlaySurfacePackage = Mockito.mock(SurfacePackage.class);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockOverlaySurfacePackage));
+
         IGameSessionController gameSessionController = getOnlyElement(
                 mFakeGameSessionService.getCapturedCreateInvocations()).mGameSessionController;
         AndroidFuture<GameScreenshotResult> resultFuture = new AndroidFuture<>();
@@ -754,18 +761,28 @@
         GameScreenshotResult result = resultFuture.get();
         assertEquals(GameScreenshotResult.GAME_SCREENSHOT_ERROR_INTERNAL_ERROR,
                 result.getStatus());
-        verify(mMockWindowManagerService).captureTaskBitmap(10);
+
+        verify(mMockWindowManagerService).captureTaskBitmap(eq(10), any());
     }
 
     @Test
     public void takeScreenshot_success() throws Exception {
-        when(mMockWindowManagerService.captureTaskBitmap(10)).thenReturn(TEST_BITMAP);
+        SurfaceControl mockOverlaySurfaceControl = Mockito.mock(SurfaceControl.class);
+        SurfaceControl[] excludeLayers = new SurfaceControl[1];
+        excludeLayers[0] = mockOverlaySurfaceControl;
+        when(mMockWindowManagerService.captureTaskBitmap(eq(10), any())).thenReturn(TEST_BITMAP);
 
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
         mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
+        FakeGameSession gameSession10 = new FakeGameSession();
+        SurfacePackage mockOverlaySurfacePackage = Mockito.mock(SurfacePackage.class);
+        when(mockOverlaySurfacePackage.getSurfaceControl()).thenReturn(mockOverlaySurfaceControl);
+        mFakeGameSessionService.removePendingFutureForTaskId(10)
+                .complete(new CreateGameSessionResult(gameSession10, mockOverlaySurfacePackage));
+
         IGameSessionController gameSessionController = getOnlyElement(
                 mFakeGameSessionService.getCapturedCreateInvocations()).mGameSessionController;
         AndroidFuture<GameScreenshotResult> resultFuture = new AndroidFuture<>();
diff --git a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java
new file mode 100644
index 0000000..fa3e05a
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2022 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.sensorprivacy;
+
+import static android.app.AppOpsManager.OPSTR_CAMERA;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.times;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightsManager;
+import android.hardware.lights.LightsRequest;
+import android.permission.PermissionManager;
+import android.util.ArraySet;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class CameraPrivacyLightControllerTest {
+
+    private MockitoSession mMockitoSession;
+
+    @Mock
+    private Context mContext;
+
+    @Mock
+    private LightsManager mLightsManager;
+
+    @Mock
+    private AppOpsManager mAppOpsManager;
+
+    @Mock
+    private LightsManager.LightsSession mLightsSession;
+
+    private ArgumentCaptor<AppOpsManager.OnOpActiveChangedListener> mAppOpsListenerCaptor =
+            ArgumentCaptor.forClass(AppOpsManager.OnOpActiveChangedListener.class);
+
+    private ArgumentCaptor<LightsRequest> mLightsRequestCaptor =
+            ArgumentCaptor.forClass(LightsRequest.class);
+
+    private Set<String> mExemptedPackages = new ArraySet<>();
+    private List<Light> mLights = new ArrayList<>();
+
+    private int mNextLightId = 1;
+
+    @Before
+    public void setUp() {
+        mMockitoSession = ExtendedMockito.mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.WARN)
+                .spyStatic(PermissionManager.class)
+                .startMocking();
+
+        doReturn(mLightsManager).when(mContext).getSystemService(LightsManager.class);
+        doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
+
+        doReturn(mLights).when(mLightsManager).getLights();
+        doReturn(mLightsSession).when(mLightsManager).openSession(anyInt());
+
+        doReturn(mExemptedPackages)
+                .when(() -> PermissionManager.getIndicatorExemptedPackages(any()));
+    }
+
+    @After
+    public void tearDown() {
+        mExemptedPackages.clear();
+        mLights.clear();
+
+        mMockitoSession.finishMocking();
+    }
+
+    @Test
+    public void testAppsOpsListenerNotRegisteredWithoutCameraLights() {
+        mLights.add(getNextLight(false));
+        new CameraPrivacyLightController(mContext);
+
+        verify(mAppOpsManager, times(0)).startWatchingActive(any(), any(), any());
+    }
+
+    @Test
+    public void testAppsOpsListenerRegisteredWithCameraLight() {
+        mLights.add(getNextLight(true));
+
+        new CameraPrivacyLightController(mContext);
+
+        verify(mAppOpsManager, times(1)).startWatchingActive(any(), any(), any());
+    }
+
+    @Test
+    public void testAllCameraLightsAreRequestedOnOpActive() {
+        Random r = new Random(0);
+        for (int i = 0; i < 30; i++) {
+            mLights.add(getNextLight(r.nextBoolean()));
+        }
+
+        new CameraPrivacyLightController(mContext);
+
+        // Verify no session has been opened at this point.
+        verify(mLightsManager, times(0)).openSession(anyInt());
+
+        // Set camera op as active.
+        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
+        mAppOpsListenerCaptor.getValue().onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true);
+
+        // Verify session has been opened exactly once
+        verify(mLightsManager, times(1)).openSession(anyInt());
+
+        verify(mLightsSession).requestLights(mLightsRequestCaptor.capture());
+        assertEquals("requestLights() not invoked exactly once",
+                1, mLightsRequestCaptor.getAllValues().size());
+
+        List<Integer> expectedCameraLightIds = mLights.stream()
+                .filter(l -> l.getType() == Light.LIGHT_TYPE_CAMERA)
+                .map(l -> l.getId())
+                .collect(Collectors.toList());
+        List<Integer> lightsRequestLightIds = mLightsRequestCaptor.getValue().getLights();
+
+        // We don't own lights framework, don't assume it will retain order
+        lightsRequestLightIds.sort(Integer::compare);
+        expectedCameraLightIds.sort(Integer::compare);
+
+        assertEquals(expectedCameraLightIds, lightsRequestLightIds);
+    }
+
+    @Test
+    public void testWillOnlyOpenOnceWhenTwoPackagesStartOp() {
+        mLights.add(getNextLight(true));
+
+        new CameraPrivacyLightController(mContext);
+
+        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
+
+        AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue();
+        listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true);
+        verify(mLightsManager, times(1)).openSession(anyInt());
+        listener.onOpActiveChanged(OPSTR_CAMERA, 10102, "pkg2", true);
+        verify(mLightsManager, times(1)).openSession(anyInt());
+    }
+
+    @Test
+    public void testWillCloseOnFinishOp() {
+        mLights.add(getNextLight(true));
+
+        new CameraPrivacyLightController(mContext);
+
+        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
+
+        AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue();
+        listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true);
+
+        verify(mLightsSession, times(0)).close();
+        listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", false);
+        verify(mLightsSession, times(1)).close();
+    }
+
+    @Test
+    public void testWillCloseOnFinishOpForAllPackages() {
+        mLights.add(getNextLight(true));
+
+        new CameraPrivacyLightController(mContext);
+
+        int numUids = 100;
+        List<Integer> uids = new ArrayList<>(numUids);
+        for (int i = 0; i < numUids; i++) {
+            uids.add(10001 + i);
+        }
+
+        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
+
+        AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue();
+
+        for (int i = 0; i < numUids; i++) {
+            listener.onOpActiveChanged(OPSTR_CAMERA, uids.get(i), "pkg" + (int) uids.get(i), true);
+        }
+
+        // Change the order which their ops are finished
+        Collections.shuffle(uids, new Random(0));
+
+        for (int i = 0; i < numUids - 1; i++) {
+            listener.onOpActiveChanged(OPSTR_CAMERA, uids.get(i), "pkg" + (int) uids.get(i), false);
+        }
+
+        verify(mLightsSession, times(0)).close();
+        int lastUid = uids.get(numUids - 1);
+        listener.onOpActiveChanged(OPSTR_CAMERA, lastUid, "pkg" + lastUid, false);
+        verify(mLightsSession, times(1)).close();
+    }
+
+    @Test
+    public void testWontOpenForExemptedPackage() {
+        mLights.add(getNextLight(true));
+        mExemptedPackages.add("pkg1");
+
+        new CameraPrivacyLightController(mContext);
+
+        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
+
+        AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue();
+        listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true);
+        verify(mLightsManager, times(0)).openSession(anyInt());
+    }
+
+    private Light getNextLight(boolean cameraType) {
+        Light light = ExtendedMockito.mock(Light.class);
+        if (cameraType) {
+            doReturn(Light.LIGHT_TYPE_CAMERA).when(light).getType();
+        } else {
+            doReturn(Light.LIGHT_TYPE_MICROPHONE).when(light).getType();
+        }
+        doReturn(mNextLightId++).when(light).getId();
+        return light;
+    }
+}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 53cab9e..d9f73d9 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -130,19 +130,6 @@
                android:resource="@xml/test_account_type2_authenticator"/>
         </service>
 
-        <service
-            android:name="com.android.server.dreams.TestDreamService"
-            android:exported="false"
-            android:label="Test Dream" >
-            <intent-filter>
-                <action android:name="android.service.dreams.DreamService" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-            <meta-data
-                android:name="android.service.dream"
-                android:resource="@xml/test_dream_metadata" />
-        </service>
-
         <receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
              android:permission="android.permission.BIND_DEVICE_ADMIN"
              android:exported="true">
diff --git a/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
new file mode 100644
index 0000000..0e84e04
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.SystemProperties;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileDescriptor;
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(AndroidJUnit4.class)
+public class BinaryTransparencyServiceTest {
+    private Context mContext;
+    private BinaryTransparencyService mBinaryTransparencyService;
+    private BinaryTransparencyService.BinaryTransparencyServiceImpl mTestInterface;
+
+    @Before
+    public void setUp() {
+        mContext = ApplicationProvider.getApplicationContext();
+        mBinaryTransparencyService = new BinaryTransparencyService(mContext);
+        mTestInterface = mBinaryTransparencyService.new BinaryTransparencyServiceImpl();
+    }
+
+    private void prepSignedInfo() {
+        // simulate what happens on boot completed phase
+        mBinaryTransparencyService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+    }
+
+    private void prepApexInfo() throws RemoteException {
+        // simulates what happens to apex info after computations are done.
+        String[] args = {"get", "apex_info"};
+        mTestInterface.onShellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
+                args, null, new ResultReceiver(null));
+    }
+
+    @Test
+    public void getSignedImageInfo_preInitialize_returnsUninitializedString() {
+        String result = mTestInterface.getSignedImageInfo();
+        Assert.assertNotNull("VBMeta digest value should not be null", result);
+        Assert.assertEquals(BinaryTransparencyService.VBMETA_DIGEST_UNINITIALIZED, result);
+    }
+
+    @Test
+    public void getSignedImageInfo_postInitialize_returnsNonErrorStrings() {
+        prepSignedInfo();
+        String result = mTestInterface.getSignedImageInfo();
+        Assert.assertNotNull("Initialized VBMeta digest string should not be null", result);
+        Assert.assertNotEquals("VBMeta digest value is uninitialized",
+                BinaryTransparencyService.VBMETA_DIGEST_UNINITIALIZED, result);
+        Assert.assertNotEquals("VBMeta value should not be unavailable",
+                BinaryTransparencyService.VBMETA_DIGEST_UNAVAILABLE, result);
+    }
+
+    @Test
+    public void getSignedImageInfo_postInitialize_returnsCorrectValue() {
+        prepSignedInfo();
+        String result = mTestInterface.getSignedImageInfo();
+        Assert.assertEquals(
+                SystemProperties.get(BinaryTransparencyService.SYSPROP_NAME_VBETA_DIGEST,
+                        BinaryTransparencyService.VBMETA_DIGEST_UNAVAILABLE), result);
+    }
+
+    @Test
+    public void getApexInfo_postInitialize_returnsValidEntries() throws RemoteException {
+        prepApexInfo();
+        Map result = mTestInterface.getApexInfo();
+        Assert.assertNotNull("Apex info map should not be null", result);
+        Assert.assertFalse("Apex info map should not be empty", result.isEmpty());
+    }
+
+    @Test
+    public void getApexInfo_postInitialize_returnsActualApexs()
+            throws RemoteException, PackageManager.NameNotFoundException {
+        prepApexInfo();
+        Map result = mTestInterface.getApexInfo();
+
+        PackageManager pm = mContext.getPackageManager();
+        Assert.assertNotNull(pm);
+        HashMap<PackageInfo, String> castedResult = (HashMap<PackageInfo, String>) result;
+        for (PackageInfo packageInfo : castedResult.keySet()) {
+            Assert.assertTrue(packageInfo.packageName + "is not an APEX!", packageInfo.isApex);
+        }
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java
index 96103e3..d95c9ac 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerUtilsTest.java
@@ -17,7 +17,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertTrue;
 
 import androidx.test.filters.SmallTest;
 
@@ -89,18 +89,20 @@
     }
 
     @Test
-    public void testSheckShouldSamplePackage() {
+    public void testCheckShouldSamplePackage() {
         // Just make sure checkShouldSamplePackage is actually working...
+        assertFailure(() -> checkShouldSamplePackage(0.3f, 0.6f, false, true));
+        assertFailure(() -> checkShouldSamplePackage(0.6f, 0.3f, true, false));
+    }
+
+    private static void assertFailure(Runnable r) {
+        boolean failed = false;
         try {
-            checkShouldSamplePackage(0.3f, 0.6f, false, true);
-            fail();
-        } catch (AssertionError expected) {
+            r.run();
+        } catch (AssertionError e) {
+            failed = true;
         }
-        try {
-            checkShouldSamplePackage(0.6f, 0.3f, true, false);
-            fail();
-        } catch (AssertionError expected) {
-        }
+        assertTrue(failed);
     }
 
     private void checkShouldSamplePackage(float inputSampleRate, float expectedRate,
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index e1aa08d..5b3a128 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -29,6 +29,8 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.longThat;
 import static org.mockito.Mockito.doAnswer;
@@ -38,6 +40,8 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.IActivityManager;
+import android.app.usage.StorageStats;
+import android.app.usage.StorageStatsManager;
 import android.app.usage.UsageEvents.Event;
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
@@ -48,6 +52,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
@@ -68,10 +73,12 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 import java.util.concurrent.Executor;
 
 /**
@@ -104,6 +111,8 @@
     @Mock
     private UserManager mUserManager;
     @Mock
+    private StorageStatsManager mStorageStatsManager;
+    @Mock
     private HibernationStateDiskStore<UserLevelState> mUserLevelDiskStore;
     @Mock
     private UsageStatsManagerInternal mUsageStatsManagerInternal;
@@ -115,7 +124,7 @@
     private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor;
 
     @Before
-    public void setUp() throws RemoteException {
+    public void setUp() throws RemoteException, PackageManager.NameNotFoundException, IOException {
         // Share class loader to allow access to package-private classes
         System.setProperty("dexmaker.share_classloader", "true");
         MockitoAnnotations.initMocks(this);
@@ -140,6 +149,11 @@
         packages.add(makePackageInfo(PACKAGE_NAME_3));
         doReturn(new ParceledListSlice<>(packages)).when(mIPackageManager).getInstalledPackages(
                 longThat(arg -> (arg & MATCH_ANY_USER) != 0), anyInt());
+        doReturn(mock(ApplicationInfo.class)).when(mIPackageManager).getApplicationInfo(
+                any(), anyLong(), anyInt());
+        StorageStats storageStats = new StorageStats();
+        doReturn(storageStats).when(mStorageStatsManager).queryStatsForPackage(
+                (UUID) any(), anyString(), any());
         mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
         UserInfo userInfo = addUser(USER_ID_1);
@@ -235,6 +249,29 @@
     }
 
     @Test
+    public void testGetHibernatingPackagesForUser_doesNotReturnPackagesThatArentVisible()
+            throws RemoteException {
+        // GIVEN an unlocked user with all packages installed but only some are visible to the
+        // caller
+        UserInfo userInfo =
+                addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3});
+        doReturn(false).when(mPackageManagerInternal).canQueryPackage(anyInt(), eq(PACKAGE_NAME_2));
+        doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
+        mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
+
+        // WHEN packages are hibernated for the user
+        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
+        mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_2, USER_ID_2, true);
+
+        // THEN the hibernating packages returned does not contain the package that was not visible
+        List<String> hibernatingPackages =
+                mAppHibernationService.getHibernatingPackagesForUser(USER_ID_2);
+        assertEquals(1, hibernatingPackages.size());
+        assertTrue(hibernatingPackages.contains(PACKAGE_NAME_1));
+        assertFalse(hibernatingPackages.contains(PACKAGE_NAME_2));
+    }
+
+    @Test
     public void testUserLevelStatesInitializedFromDisk() throws RemoteException {
         // GIVEN states stored on disk that match with package manager's force-stop states
         List<UserLevelState> diskStates = new ArrayList<>();
@@ -381,18 +418,31 @@
     }
 
     @Test
-    public void testGetHibernationStatsForUser_getsStatsForPackage() {
-        // GIVEN a package is hibernating globally and for a user
+    public void testGetHibernationStatsForUser_getsStatsForPackage()
+            throws PackageManager.NameNotFoundException, IOException, RemoteException {
+        // GIVEN a package is hibernating globally and for a user with some storage saved
+        final long cacheSavings = 1000;
+        StorageStats storageStats = new StorageStats();
+        storageStats.cacheBytes = cacheSavings;
+        doReturn(storageStats).when(mStorageStatsManager).queryStatsForPackage(
+                (UUID) any(), eq(PACKAGE_NAME_1), any());
+        final long oatDeletionSavings = 2000;
+        doReturn(oatDeletionSavings).when(mPackageManagerInternal).deleteOatArtifactsOfPackage(
+                PACKAGE_NAME_1);
+
         mAppHibernationService.setHibernatingGlobally(PACKAGE_NAME_1, true);
         mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_1, true);
 
         // WHEN we ask for the hibernation stats for the package
-        Map<String, HibernationStats> stats =
+        Map<String, HibernationStats> statsMap =
                 mAppHibernationService.getHibernationStatsForUser(
                         Set.of(PACKAGE_NAME_1), USER_ID_1);
 
-        // THEN the stats exist for the package
-        assertTrue(stats.containsKey(PACKAGE_NAME_1));
+        // THEN the stats exist for the package and add up to the OAT deletion and cache deletion
+        // savings
+        HibernationStats stats = statsMap.get(PACKAGE_NAME_1);
+        assertNotNull(stats);
+        assertEquals(cacheSavings + oatDeletionSavings, stats.getDiskBytesSaved());
     }
 
     @Test
@@ -519,6 +569,11 @@
         }
 
         @Override
+        public StorageStatsManager getStorageStatsManager() {
+            return mStorageStatsManager;
+        }
+
+        @Override
         public UsageStatsManagerInternal getUsageStatsManagerInternal() {
             return mUsageStatsManagerInternal;
         }
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index bdea679..dad9fe8 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -28,6 +28,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.content.Intent;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.BluetoothProfileConnectionInfo;
@@ -186,8 +187,9 @@
         doNothing().when(mSpySystemServer).broadcastStickyIntentToCurrentProfileGroup(
                 any(Intent.class));
 
-        mSpyDevInventory.setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
-                AudioService.CONNECTION_STATE_CONNECTED, address, name, caller);
+        mSpyDevInventory.setWiredDeviceConnectionState(new AudioDeviceAttributes(
+                        AudioSystem.DEVICE_OUT_WIRED_HEADSET, address, name),
+                AudioService.CONNECTION_STATE_CONNECTED, caller);
         Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
 
         // Verify that the sticky intent is broadcasted
@@ -246,11 +248,11 @@
      */
     private void checkSingleSystemConnection(BluetoothDevice btDevice) throws Exception {
         final String expectedName = btDevice.getName() == null ? "" : btDevice.getName();
+        AudioDeviceAttributes expected = new AudioDeviceAttributes(
+                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, btDevice.getAddress(), expectedName);
         verify(mSpyAudioSystem, times(1)).setDeviceConnectionState(
-                ArgumentMatchers.eq(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
+                ArgumentMatchers.argThat(x -> x.equalTypeAddress(expected)),
                 ArgumentMatchers.eq(AudioSystem.DEVICE_STATE_AVAILABLE),
-                ArgumentMatchers.eq(btDevice.getAddress()),
-                ArgumentMatchers.eq(expectedName),
                 anyInt() /*codec*/);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
index 8d706cb..1f355b0 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
@@ -48,11 +48,10 @@
     //-----------------------------------------------------------------
     // Overrides of AudioSystemAdapter
     @Override
-    public int setDeviceConnectionState(int device, int state, String deviceAddress,
-            String deviceName, int codecFormat) {
-        Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, %s, %s, 0x%s",
-                Integer.toHexString(device), state, deviceAddress, deviceName,
-                Integer.toHexString(codecFormat)));
+    public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+            int codecFormat) {
+        Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, 0x%s",
+                attributes.toString(), state, Integer.toHexString(codecFormat)));
         return AudioSystem.AUDIO_STATUS_OK;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
index 83fa7ac..b4bb04d 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
@@ -21,7 +21,6 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.hardware.display.DisplayManagerInternal;
@@ -30,7 +29,6 @@
 import android.hardware.input.InputManagerInternal;
 import android.os.Binder;
 import android.os.IBinder;
-import android.os.IInputConstants;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
 import android.view.DisplayInfo;
@@ -81,17 +79,15 @@
     }
 
     @Test
-    public void unregisterInputDevice_allMiceUnregistered_unsetValues() {
+    public void unregisterInputDevice_allMiceUnregistered_clearPointerDisplayId() {
         final IBinder deviceToken = new Binder();
         mInputController.createMouse("name", /*vendorId= */ 1, /*productId= */ 1, deviceToken,
                 /* displayId= */ 1);
         verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
-        verify(mInputManagerInternalMock).setPointerAcceleration(eq(1f));
+        doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         mInputController.unregisterInputDevice(deviceToken);
         verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(
                 eq(Display.INVALID_DISPLAY));
-        verify(mInputManagerInternalMock).setPointerAcceleration(
-                eq((float) IInputConstants.DEFAULT_POINTER_ACCELERATION));
     }
 
     @Test
@@ -100,14 +96,11 @@
         mInputController.createMouse("name", /*vendorId= */ 1, /*productId= */ 1, deviceToken,
                 /* displayId= */ 1);
         verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
-        verify(mInputManagerInternalMock).setPointerAcceleration(eq(1f));
         final IBinder deviceToken2 = new Binder();
         mInputController.createMouse("name", /*vendorId= */ 1, /*productId= */ 1, deviceToken2,
                 /* displayId= */ 2);
         verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(2));
         mInputController.unregisterInputDevice(deviceToken);
         verify(mInputManagerInternalMock).setVirtualMousePointerDisplayId(eq(1));
-        verify(mInputManagerInternalMock, times(0)).setPointerAcceleration(
-                eq((float) IInputConstants.DEFAULT_POINTER_ACCELERATION));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 33540c8..3b4aece 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -19,6 +19,8 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
@@ -27,6 +29,7 @@
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertThrows;
@@ -117,6 +120,8 @@
         LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
 
         doNothing().when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt());
+        doNothing().when(mInputManagerInternalMock).setPointerAcceleration(anyFloat(), anyInt());
+        doNothing().when(mInputManagerInternalMock).setPointerIconVisible(anyBoolean(), anyInt());
         LocalServices.removeServiceForTest(InputManagerInternal.class);
         LocalServices.addService(InputManagerInternal.class, mInputManagerInternalMock);
 
@@ -353,7 +358,7 @@
         mInputController.mInputDeviceDescriptors.put(BINDER,
                 new InputController.InputDeviceDescriptor(fd, () -> {}, /* type= */ 2,
                         /* displayId= */ 1, PHYS));
-        mInputController.mActivePointerDisplayId = 1;
+        doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         mDeviceImpl.sendButtonEvent(BINDER, new VirtualMouseButtonEvent.Builder()
                 .setButtonCode(buttonCode)
                 .setAction(action).build());
@@ -394,7 +399,7 @@
         mInputController.mInputDeviceDescriptors.put(BINDER,
                 new InputController.InputDeviceDescriptor(fd, () -> {}, /* type= */ 2,
                         /* displayId= */ 1, PHYS));
-        mInputController.mActivePointerDisplayId = 1;
+        doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         mDeviceImpl.sendRelativeEvent(BINDER, new VirtualMouseRelativeEvent.Builder()
                 .setRelativeX(x).setRelativeY(y).build());
         verify(mNativeWrapperMock).writeRelativeEvent(fd, x, y);
@@ -435,7 +440,7 @@
         mInputController.mInputDeviceDescriptors.put(BINDER,
                 new InputController.InputDeviceDescriptor(fd, () -> {}, /* type= */ 2,
                         /* displayId= */ 1, PHYS));
-        mInputController.mActivePointerDisplayId = 1;
+        doReturn(1).when(mInputManagerInternalMock).getVirtualMousePointerDisplayId();
         mDeviceImpl.sendScrollEvent(BINDER, new VirtualMouseScrollEvent.Builder()
                 .setXAxisMovement(x)
                 .setYAxisMovement(y).build());
@@ -508,4 +513,19 @@
         verify(mNativeWrapperMock).writeTouchEvent(fd, pointerId, toolType, action, x, y, pressure,
                 majorAxisSize);
     }
+
+    @Test
+    public void setShowPointerIcon_setsValueForAllDisplays() {
+        mDeviceImpl.mVirtualDisplayIds.add(1);
+        mDeviceImpl.mVirtualDisplayIds.add(2);
+        mDeviceImpl.mVirtualDisplayIds.add(3);
+        mDeviceImpl.createVirtualMouse(1, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
+        mDeviceImpl.createVirtualMouse(2, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
+        mDeviceImpl.createVirtualMouse(3, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
+        mDeviceImpl.setShowPointerIcon(false);
+        verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(false), anyInt());
+        verify(mInputManagerInternalMock, never()).setPointerIconVisible(eq(true), anyInt());
+        mDeviceImpl.setShowPointerIcon(true);
+        verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(true), anyInt());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index c877bd1..48e2122 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -120,6 +120,7 @@
 import android.hardware.usb.UsbManager;
 import android.net.ProfileNetworkPreference;
 import android.net.Uri;
+import android.net.wifi.WifiSsid;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
@@ -164,6 +165,7 @@
 import java.io.File;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -7779,6 +7781,7 @@
 
                 verify(getServices().userManagerInternal, never())
                         .setDevicePolicyUserRestrictions(anyInt(), any(), any(), anyBoolean());
+                DpmTestUtils.assertRestrictions(new Bundle(), dpm.getUserRestrictions(admin1));
             }
         }
     }
@@ -7810,6 +7813,9 @@
                                 eq(true));
                 reset(getServices().userManagerInternal);
 
+                DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(restriction),
+                        dpm.getUserRestrictions(admin1));
+
                 dpm.clearUserRestriction(admin1, restriction);
                 reset(getServices().userManagerInternal);
             }
@@ -8056,6 +8062,28 @@
     }
 
     @Test
+    public void testGetPermissionGrantState_financeDo_notReadPhoneStatePermission_throwsException()
+            throws Exception {
+        setDeviceOwner();
+        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
+
+        assertExpectException(SecurityException.class, /* messageRegex= */ null,
+                () -> dpm.getPermissionGrantState(admin1, admin1.getPackageName(),
+                        permission.READ_CALENDAR));
+    }
+
+    @Test
+    public void testGetPermissionGrantState_financeDo_notDeviceOwnerPackage_throwsException()
+            throws Exception {
+        setDeviceOwner();
+        dpm.setDeviceOwnerType(admin1, DEVICE_OWNER_TYPE_FINANCED);
+
+        assertExpectException(SecurityException.class, /* messageRegex= */ null,
+                () -> dpm.getPermissionGrantState(admin1, "com.android.foo.package",
+                        permission.READ_PHONE_STATE));
+    }
+
+    @Test
     public void testSetUsbDataSignalingEnabled_noDeviceOwnerOrPoOfOrgOwnedDevice() {
         assertThrows(SecurityException.class,
                 () -> dpm.setUsbDataSignalingEnabled(true));
@@ -8334,8 +8362,10 @@
 
     @Test
     public void testSetSsidAllowlist_noDeviceOwnerOrPoOfOrgOwnedDevice() {
-        final Set<String> ssids = Collections.singleton("ssid1");
-        WifiSsidPolicy policy = WifiSsidPolicy.createAllowlistPolicy(ssids);
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
+        WifiSsidPolicy policy = new WifiSsidPolicy(
+                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids);
         assertThrows(SecurityException.class, () -> dpm.setWifiSsidPolicy(policy));
     }
 
@@ -8343,8 +8373,10 @@
     public void testSetSsidAllowlist_asDeviceOwner() throws Exception {
         setDeviceOwner();
 
-        final Set<String> ssids = Collections.singleton("ssid1");
-        WifiSsidPolicy policy = WifiSsidPolicy.createAllowlistPolicy(ssids);
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
+        WifiSsidPolicy policy = new WifiSsidPolicy(
+                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids);
         dpm.setWifiSsidPolicy(policy);
         assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
         assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo(
@@ -8359,8 +8391,12 @@
         configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
         mContext.binder.callingUid = managedProfileAdminUid;
 
-        final Set<String> ssids = new ArraySet<>(Arrays.asList("ssid1", "ssid2", "ssid3"));
-        WifiSsidPolicy policy = WifiSsidPolicy.createAllowlistPolicy(ssids);
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)),
+                        WifiSsid.fromBytes("ssid2".getBytes(StandardCharsets.UTF_8)),
+                        WifiSsid.fromBytes("ssid3".getBytes(StandardCharsets.UTF_8))));
+        WifiSsidPolicy policy = new WifiSsidPolicy(
+                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids);
         dpm.setWifiSsidPolicy(policy);
         assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
         assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo(
@@ -8371,15 +8407,17 @@
     public void testSetSsidAllowlist_emptyList() throws Exception {
         setDeviceOwner();
 
-        final Set<String> ssids = new ArraySet<>();
+        final Set<WifiSsid> ssids = new ArraySet<>();
         assertThrows(IllegalArgumentException.class,
-                () -> WifiSsidPolicy.createAllowlistPolicy(ssids));
+                () -> new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST, ssids));
     }
 
     @Test
     public void testSetSsidDenylist_noDeviceOwnerOrPoOfOrgOwnedDevice() {
-        final Set<String> ssids = Collections.singleton("ssid1");
-        WifiSsidPolicy policy = WifiSsidPolicy.createDenylistPolicy(ssids);
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
+        WifiSsidPolicy policy = new WifiSsidPolicy(
+                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids);
         assertThrows(SecurityException.class, () -> dpm.setWifiSsidPolicy(policy));
     }
 
@@ -8387,8 +8425,10 @@
     public void testSetSsidDenylist_asDeviceOwner() throws Exception {
         setDeviceOwner();
 
-        final Set<String> ssids = Collections.singleton("ssid1");
-        WifiSsidPolicy policy = WifiSsidPolicy.createDenylistPolicy(ssids);
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8))));
+        WifiSsidPolicy policy = new WifiSsidPolicy(
+                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids);
         dpm.setWifiSsidPolicy(policy);
         assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
         assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo(
@@ -8403,8 +8443,12 @@
         configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
         mContext.binder.callingUid = managedProfileAdminUid;
 
-        final Set<String> ssids = new ArraySet<>(Arrays.asList("ssid1", "ssid2", "ssid3"));
-        WifiSsidPolicy policy = WifiSsidPolicy.createDenylistPolicy(ssids);
+        final Set<WifiSsid> ssids = new ArraySet<>(
+                Arrays.asList(WifiSsid.fromBytes("ssid1".getBytes(StandardCharsets.UTF_8)),
+                        WifiSsid.fromBytes("ssid2".getBytes(StandardCharsets.UTF_8)),
+                        WifiSsid.fromBytes("ssid3".getBytes(StandardCharsets.UTF_8))));
+        WifiSsidPolicy policy = new WifiSsidPolicy(
+                WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids);
         dpm.setWifiSsidPolicy(policy);
         assertThat(dpm.getWifiSsidPolicy().getSsids()).isEqualTo(ssids);
         assertThat(dpm.getWifiSsidPolicy().getPolicyType()).isEqualTo(
@@ -8415,9 +8459,9 @@
     public void testSetSsidDenylist_emptyList() throws Exception {
         setDeviceOwner();
 
-        final Set<String> ssids = new ArraySet<>();
+        final Set<WifiSsid> ssids = new ArraySet<>();
         assertThrows(IllegalArgumentException.class,
-                () -> WifiSsidPolicy.createDenylistPolicy(ssids));
+                () -> new WifiSsidPolicy(WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST, ssids));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index 24a4751..f352de4 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -36,8 +36,11 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 
 import java.util.Arrays;
 
@@ -147,11 +150,14 @@
 
     private static final float TOLERANCE = 0.0001f;
 
+    @Mock
+    DisplayWhiteBalanceController mMockDwbc;
+
     @Test
     public void testSimpleStrategyMappingAtControlPoints() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNotNull("BrightnessMappingStrategy should not be null", simple);
         for (int i = 0; i < LUX_LEVELS.length; i++) {
             final float expectedLevel = MathUtils.map(PowerManager.BRIGHTNESS_OFF + 1,
@@ -166,7 +172,7 @@
     public void testSimpleStrategyMappingBetweenControlPoints() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNotNull("BrightnessMappingStrategy should not be null", simple);
         for (int i = 1; i < LUX_LEVELS.length; i++) {
             final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
@@ -181,7 +187,7 @@
     public void testSimpleStrategyIgnoresNewConfiguration() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
 
         final float[] lux = { 0f, 1f };
         final float[] nits = { 0, PowerManager.BRIGHTNESS_ON };
@@ -196,7 +202,7 @@
     public void testSimpleStrategyIgnoresNullConfiguration() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
 
         strategy.setBrightnessConfiguration(null);
         final int N = DISPLAY_LEVELS_BACKLIGHT.length;
@@ -210,7 +216,7 @@
     public void testPhysicalStrategyMappingAtControlPoints() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNotNull("BrightnessMappingStrategy should not be null", physical);
         for (int i = 0; i < LUX_LEVELS.length; i++) {
             final float expectedLevel = MathUtils.map(DISPLAY_RANGE_NITS[0], DISPLAY_RANGE_NITS[1],
@@ -227,7 +233,7 @@
     public void testPhysicalStrategyMappingBetweenControlPoints() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
         DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
-        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNotNull("BrightnessMappingStrategy should not be null", physical);
         Spline brightnessToNits =
                 Spline.createSpline(BACKLIGHT_RANGE_ZERO_TO_ONE, DISPLAY_RANGE_NITS);
@@ -244,7 +250,7 @@
     public void testPhysicalStrategyUsesNewConfigurations() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
 
         final float[] lux = { 0f, 1f };
         final float[] nits = {
@@ -269,7 +275,7 @@
     public void testPhysicalStrategyRecalculateSplines() {
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
         DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS);
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         float[] adjustedNits50p = new float[DISPLAY_RANGE_NITS.length];
         for (int i = 0; i < DISPLAY_RANGE_NITS.length; i++) {
             adjustedNits50p[i] = DISPLAY_RANGE_NITS[i] * 0.5f;
@@ -301,7 +307,7 @@
         Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
                 DISPLAY_LEVELS_NITS);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertTrue(strategy instanceof BrightnessMappingStrategy.PhysicalMappingStrategy);
     }
 
@@ -314,13 +320,13 @@
         lux[idx+1] = tmp;
         Resources res = createResources(lux, DISPLAY_LEVELS_NITS);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(strategy);
 
         // And make sure we get the same result even if it's monotone but not increasing.
         lux[idx] = lux[idx+1];
         res = createResources(lux, DISPLAY_LEVELS_NITS);
-        strategy = BrightnessMappingStrategy.create(res, ddc);
+        strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(strategy);
     }
 
@@ -333,11 +339,11 @@
         lux[lux.length - 1] = lux[lux.length - 2] + 1;
         Resources res = createResources(lux, DISPLAY_LEVELS_NITS);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(strategy);
 
         res = createResources(lux, DISPLAY_LEVELS_BACKLIGHT);
-        strategy = BrightnessMappingStrategy.create(res, ddc);
+        strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(strategy);
 
         // Extra backlight level
@@ -345,14 +351,14 @@
                 DISPLAY_LEVELS_BACKLIGHT, DISPLAY_LEVELS_BACKLIGHT.length+1);
         backlight[backlight.length - 1] = backlight[backlight.length - 2] + 1;
         res = createResources(LUX_LEVELS, backlight);
-        strategy = BrightnessMappingStrategy.create(res, ddc);
+        strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(strategy);
 
         // Extra nits level
         final float[] nits = Arrays.copyOf(DISPLAY_RANGE_NITS, DISPLAY_LEVELS_NITS.length+1);
         nits[nits.length - 1] = nits[nits.length - 2] + 1;
         res = createResources(LUX_LEVELS, nits);
-        strategy = BrightnessMappingStrategy.create(res, ddc);
+        strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(strategy);
     }
 
@@ -361,17 +367,17 @@
         Resources res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
                 DISPLAY_LEVELS_NITS);
         DisplayDeviceConfig ddc = createDdc(EMPTY_FLOAT_ARRAY /*nitsRange*/);
-        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
+        BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(physical);
 
         res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
                 DISPLAY_LEVELS_NITS);
-        physical = BrightnessMappingStrategy.create(res, ddc);
+        physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(physical);
 
         res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
                 DISPLAY_LEVELS_NITS);
-        physical = BrightnessMappingStrategy.create(res, ddc);
+        physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
         assertNull(physical);
     }
 
@@ -380,10 +386,10 @@
         Resources res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
                 DISPLAY_LEVELS_NITS);
         DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
-        assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc));
+        assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc, mMockDwbc));
         ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
         res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
-        assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc));
+        assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc, mMockDwbc));
     }
 
     @Test
@@ -394,7 +400,7 @@
         // Create an idle mode bms
         // This will fail if it tries to fetch the wrong configuration.
         BrightnessMappingStrategy bms = BrightnessMappingStrategy.createForIdleMode(res, ddc,
-                null);
+                mMockDwbc);
         assertNotNull("BrightnessMappingStrategy should not be null", bms);
 
         // Ensure that the config is the one we set
@@ -586,7 +592,8 @@
 
         Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
+                mMockDwbc);
         // Let's start with a validity check:
         assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
         assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -614,7 +621,8 @@
         final float y3 = GAMMA_CORRECTION_SPLINE.interpolate(x3);
         Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
+                mMockDwbc);
         // Validity check:
         assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
         assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -639,7 +647,8 @@
         // just make sure the adjustment reflects the change.
         Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
+                mMockDwbc);
         assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
         strategy.addUserDataPoint(2500, 1.0f);
         assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
@@ -660,7 +669,8 @@
         final float y4 = GAMMA_CORRECTION_SPLINE.interpolate(x4);
         Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
         DisplayDeviceConfig ddc = createDdc();
-        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
+                mMockDwbc);
         // Validity, as per tradition:
         assertEquals(y0, strategy.getBrightness(x0), 0.0001f /* tolerance */);
         assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 6203c2f..53fa3e2 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -22,11 +22,14 @@
 import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
 import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;
 
+
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
 import static com.android.server.display.AutomaticBrightnessController
                                                       .AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE;
 
+import static com.android.server.display.DisplayDeviceConfig.HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+
 import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
 
 import static org.junit.Assert.assertEquals;
@@ -111,7 +114,8 @@
     private static final HighBrightnessModeData DEFAULT_HBM_DATA =
             new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS,
                     TIME_ALLOWED_IN_WINDOW_MILLIS, TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS,
-                    THERMAL_STATUS_LIMIT, ALLOW_IN_LOW_POWER_MODE);
+                    THERMAL_STATUS_LIMIT, ALLOW_IN_LOW_POWER_MODE,
+                    HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT);
 
     @Before
     public void setUp() {
@@ -136,7 +140,7 @@
         initHandler(null);
         final HighBrightnessModeController hbmc = new HighBrightnessModeController(
                 mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
-                mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, () -> {}, mContextSpy);
+                mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
         assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
         assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f);
     }
@@ -146,7 +150,7 @@
         initHandler(null);
         final HighBrightnessModeController hbmc = new HighBrightnessModeController(
                 mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
-                mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, () -> {}, mContextSpy);
+                mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
         hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
         hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
         assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
@@ -703,7 +707,7 @@
         initHandler(clock);
         return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
                 DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
-                DEFAULT_HBM_DATA, () -> {}, mContextSpy);
+                DEFAULT_HBM_DATA, null, () -> {}, mContextSpy);
     }
 
     private void initHandler(OffsettableClock clock) {
diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
deleted file mode 100644
index b489a2a..0000000
--- a/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2022 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.dreams;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.service.dreams.DreamService;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class DreamServiceTest {
-    @Test
-    public void testMetadataParsing() {
-        final String testDreamServiceComponent = "com.android.server.dreams/.TestDreamService";
-        final String testSettingsActivity = "com.android.server.dreams/.TestDreamSettingsActivity";
-
-        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
-        try {
-            final ServiceInfo si = context.getPackageManager().getServiceInfo(
-                    ComponentName.unflattenFromString(testDreamServiceComponent),
-                    PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
-            final DreamService.DreamMetadata metadata = DreamService.getDreamMetadata(context, si);
-
-            assertEquals(0, metadata.settingsActivity.compareTo(
-                    ComponentName.unflattenFromString(testSettingsActivity)));
-            assertFalse(metadata.showComplications);
-        } catch (PackageManager.NameNotFoundException e) {
-            e.printStackTrace();
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index b6c4bc2..a9812ab 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -62,6 +62,23 @@
 public class HdmiCecLocalDeviceTvTest {
     private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
 
+    private static final String[] SADS_NOT_TO_QUERY = new String[]{
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_AAC,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTS,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ATRAC,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DDP,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTSHD,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
+            HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX};
+    private static final HdmiCecMessage SAD_QUERY =
+            HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(ADDR_TV, ADDR_AUDIO_SYSTEM,
+                    new int[]{Constants.AUDIO_CODEC_LPCM, Constants.AUDIO_CODEC_DD,
+                            Constants.AUDIO_CODEC_MP3, Constants.AUDIO_CODEC_MPEG2});
+
     private HdmiControlService mHdmiControlService;
     private HdmiCecController mHdmiCecController;
     private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
@@ -136,6 +153,10 @@
         mNativeWrapper.setPhysicalAddress(mTvPhysicalAddress);
         mTestLooper.dispatchAll();
         mTvLogicalAddress = mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress();
+        for (String sad : SADS_NOT_TO_QUERY) {
+            mHdmiControlService.getHdmiCecConfig().setIntValue(
+                    sad, HdmiControlManager.QUERY_SAD_DISABLED);
+        }
         mNativeWrapper.clearResultMessages();
     }
 
@@ -442,6 +463,7 @@
                 ADDR_TV,
                 ADDR_AUDIO_SYSTEM);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
     }
 
     @Test
@@ -463,6 +485,7 @@
                 ADDR_TV,
                 ADDR_AUDIO_SYSTEM);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
     }
 
     @Test
@@ -485,6 +508,7 @@
                 ADDR_TV,
                 ADDR_AUDIO_SYSTEM);
         assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
+        assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 94cf20f..a7b045f 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -2237,7 +2237,7 @@
 
     private void setSubscriptionPlans(int subId, SubscriptionPlan[] plans, String callingPackage)
             throws InterruptedException {
-        mService.setSubscriptionPlans(subId, plans, callingPackage);
+        mService.setSubscriptionPlans(subId, plans, 0, callingPackage);
         // setSubscriptionPlans() triggers async events, wait for those to be completed before
         // moving forward as they could interfere with the tests later.
         postMsgAndWaitForCompletion();
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 7f7c716..2f5993d1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -61,7 +61,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.Map;
+import java.util.List;
 
 @SmallTest
 @Presubmit
@@ -136,9 +136,10 @@
         mApexManager.scanApexPackagesTraced(mPackageParser2,
                 ParallelPackageParser.makeExecutorService());
 
-        Map<String, String> services = mApexManager.getApexSystemServices();
+        List<ApexSystemServiceInfo> services = mApexManager.getApexSystemServices();
         assertThat(services).hasSize(1);
-        assertThat(services).containsKey("com.android.apex.test.ApexSystemService");
+        assertThat(services.stream().map(ApexSystemServiceInfo::getName).findFirst().orElse(null))
+                .matches("com.android.apex.test.ApexSystemService");
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index ac83642..ed4dee1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -43,7 +43,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.UserInfo;
-import android.content.pm.parsing.FrameworkParsingPackageUtils;
 import android.os.BaseBundle;
 import android.os.PersistableBundle;
 import android.os.Process;
@@ -87,7 +86,6 @@
 import java.io.IOException;
 import java.security.PublicKey;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
@@ -671,6 +669,23 @@
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/,
                 UUID.randomUUID());
+        origPkgSetting01.setUserState(0, 100, 1, true, false, false, false, 0, null, false,
+                false, "lastDisabledCaller", new ArraySet<>(new String[]{"enabledComponent1"}),
+                new ArraySet<>(new String[]{"disabledComponent1"}), 0, 0, "harmfulAppWarning",
+                "splashScreenTheme", 1000L);
+        final PersistableBundle appExtras1 = createPersistableBundle(
+                PACKAGE_NAME_1, 1L, 0.01, true, "appString1");
+        final PersistableBundle launcherExtras1 = createPersistableBundle(
+                PACKAGE_NAME_1, 10L, 0.1, false, "launcherString1");
+        final SuspendDialogInfo dialogInfo1 = new SuspendDialogInfo.Builder()
+                .setIcon(0x11220001)
+                .setTitle("String Title")
+                .setMessage("1st message")
+                .setNeutralButtonText(0x11220003)
+                .setNeutralButtonAction(BUTTON_ACTION_MORE_DETAILS)
+                .build();
+        origPkgSetting01.modifyUserState(0).putSuspendParams("suspendingPackage1",
+                SuspendParams.getInstanceOrNull(dialogInfo1, appExtras1, launcherExtras1));
         final PackageSetting testPkgSetting01 = new PackageSetting(
                 PACKAGE_NAME /*pkgName*/,
                 REAL_PACKAGE_NAME /*realPkgName*/,
@@ -691,6 +706,8 @@
                 UUID.randomUUID());
         testPkgSetting01.copyPackageSetting(origPkgSetting01);
         verifySettingCopy(origPkgSetting01, testPkgSetting01);
+        verifyUserStatesCopy(origPkgSetting01.readUserState(0),
+                testPkgSetting01.readUserState(0));
     }
 
     /** Update package */
@@ -724,8 +741,7 @@
         assertThat(testPkgSetting01.getFlags(), is(0));
         assertThat(testPkgSetting01.getPrivateFlags(), is(0));
         final PackageUserState userState = testPkgSetting01.readUserState(0);
-        final PackageUserState oldUserState = oldPkgSetting01.readUserState(0);
-        verifyUserState(userState, oldUserState, false /*userStateChanged*/, false /*notLaunched*/,
+        verifyUserState(userState, false /*notLaunched*/,
                 false /*stopped*/, false /*installed*/);
     }
 
@@ -760,11 +776,7 @@
         assertThat(testPkgSetting01.getFlags(), is(ApplicationInfo.FLAG_SYSTEM));
         assertThat(testPkgSetting01.getPrivateFlags(), is(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED));
         final PackageUserState userState = testPkgSetting01.readUserState(0);
-        final PackageUserState oldUserState = oldPkgSetting01.readUserState(0);
-        // WARNING: When creating a shallow copy of the PackageSetting we do NOT create
-        // new contained objects. For example, this means that changes to the user state
-        // in testPkgSetting01 will also change the user state in its copy.
-        verifyUserState(userState, oldUserState, false /*userStateChanged*/, false /*notLaunched*/,
+        verifyUserState(userState,  false /*notLaunched*/,
                 false /*stopped*/, true /*installed*/);
     }
 
@@ -839,8 +851,7 @@
         assertNotSame(testPkgSetting01.getSignatures(), originalSignatures);
         assertThat(testPkgSetting01.getVersionCode(), is(UPDATED_VERSION_CODE));
         final PackageUserState userState = testPkgSetting01.readUserState(0);
-        verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/,
-                false /*notLaunched*/, false /*stopped*/, true /*installed*/);
+        verifyUserState(userState, false /*notLaunched*/, false /*stopped*/, true /*installed*/);
     }
 
     /** Create a new non-system PackageSetting */
@@ -880,8 +891,7 @@
         assertThat(testPkgSetting01.getVersionCode(), is(INITIAL_VERSION_CODE));
         // by default, the package is considered stopped
         final PackageUserState userState = testPkgSetting01.readUserState(0);
-        verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/,
-                true /*notLaunched*/, true /*stopped*/, true /*installed*/);
+        verifyUserState(userState, true /*notLaunched*/, true /*stopped*/, true /*installed*/);
     }
 
     /** Create PackageSetting for a shared user */
@@ -923,8 +933,7 @@
         assertThat(testPkgSetting01.getSecondaryCpuAbi(), is("x86"));
         assertThat(testPkgSetting01.getVersionCode(), is(INITIAL_VERSION_CODE));
         final PackageUserState userState = testPkgSetting01.readUserState(0);
-        verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/,
-                false /*notLaunched*/, false /*stopped*/, true /*installed*/);
+        verifyUserState(userState, false /*notLaunched*/, false /*stopped*/, true /*installed*/);
     }
 
     /** Create a new PackageSetting based on a disabled package setting */
@@ -968,8 +977,7 @@
         assertNotSame(testPkgSetting01.getSignatures(), disabledSignatures);
         assertThat(testPkgSetting01.getVersionCode(), is(UPDATED_VERSION_CODE));
         final PackageUserState userState = testPkgSetting01.readUserState(0);
-        verifyUserState(userState, null /*oldUserState*/, false /*userStateChanged*/,
-                false /*notLaunched*/, false /*stopped*/, true /*installed*/);
+        verifyUserState(userState, false /*notLaunched*/, false /*stopped*/, true /*installed*/);
     }
 
     @Test
@@ -1080,29 +1088,8 @@
         assertThat(countDownLatch.getCount(), is(0L));
     }
 
-    private <T> void assertArrayEquals(T[] a, T[] b) {
-        assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b),
-                Arrays.equals(a, b));
-    }
-
-    private void assertArrayEquals(int[] a, int[] b) {
-        assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b),
-                Arrays.equals(a, b));
-    }
-
-    private void assertArrayEquals(long[] a, long[] b) {
-        assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b),
-                Arrays.equals(a, b));
-    }
-
-    private void verifyUserState(PackageUserState userState, PackageUserState oldUserState,
-            boolean userStateChanged) {
-        verifyUserState(userState, oldUserState, userStateChanged, false /*notLaunched*/,
-                false /*stopped*/, true /*installed*/);
-    }
-
-    private void verifyUserState(PackageUserState userState, PackageUserState oldUserState,
-            boolean userStateChanged, boolean notLaunched, boolean stopped, boolean installed) {
+    private void verifyUserState(PackageUserState userState,
+            boolean notLaunched, boolean stopped, boolean installed) {
         assertThat(userState.getEnabledState(), is(0));
         assertThat(userState.isHidden(), is(false));
         assertThat(userState.isInstalled(), is(installed));
@@ -1110,9 +1097,6 @@
         assertThat(userState.isStopped(), is(stopped));
         assertThat(userState.isSuspended(), is(false));
         assertThat(userState.getDistractionFlags(), is(0));
-        if (oldUserState != null) {
-            assertThat(userState.equals(oldUserState), is(not(userStateChanged)));
-        }
     }
 
     private void verifyKeySetData(PackageKeySetData originalData, PackageKeySetData testData) {
@@ -1177,6 +1161,57 @@
         assertThat(origPkgSetting.getVolumeUuid(), is(testPkgSetting.getVolumeUuid()));
     }
 
+    private void verifyUserStatesCopy(PackageUserStateInternal origPus,
+            PackageUserStateInternal testPus) {
+        assertThat(userStateEquals(origPus, testPus), is(true));
+        // Verify suspendParams are copied over
+        assertThat(origPus.getSuspendParams(), is(notNullValue()));
+        assertThat(testPus.getSuspendParams(), is(notNullValue()));
+        SuspendParams origSuspendParams = origPus.getSuspendParams().valueAt(0);
+        SuspendParams testSuspendParams = testPus.getSuspendParams().valueAt(0);
+        assertThat(origSuspendParams.getDialogInfo().equals(testSuspendParams.getDialogInfo()),
+                is(true));
+        assertThat(BaseBundle.kindofEquals(
+                origSuspendParams.getAppExtras(), testSuspendParams.getAppExtras()), is(true));
+        assertThat(BaseBundle.kindofEquals(origSuspendParams.getLauncherExtras(),
+                testSuspendParams.getLauncherExtras()), is(true));
+        // Verify that disabledComponents and enabledComponents are copied
+        assertThat(origPus.getDisabledComponents(), is(notNullValue()));
+        assertThat(origPus.getDisabledComponents().equals(testPus.getDisabledComponents()),
+                is(true));
+        assertThat(origPus.getEnabledComponents(), is(notNullValue()));
+        assertThat(origPus.getEnabledComponents().equals(testPus.getEnabledComponents()),
+                is(true));
+    }
+
+    private boolean userStateEquals(PackageUserState userState, PackageUserState oldUserState) {
+        return userState.isHidden() == oldUserState.isHidden()
+                && userState.isStopped() == oldUserState.isStopped()
+                && userState.isInstalled() == oldUserState.isInstalled()
+                && userState.isSuspended() == oldUserState.isSuspended()
+                && userState.isNotLaunched() == oldUserState.isNotLaunched()
+                && userState.isInstantApp() == oldUserState.isInstantApp()
+                && userState.isVirtualPreload() == oldUserState.isVirtualPreload()
+                && (userState.getAllOverlayPaths() != null
+                ? userState.getAllOverlayPaths().equals(oldUserState.getAllOverlayPaths())
+                : oldUserState.getOverlayPaths() == null)
+                && userState.getCeDataInode() == oldUserState.getCeDataInode()
+                && userState.getDistractionFlags() == oldUserState.getDistractionFlags()
+                && userState.getFirstInstallTime() == oldUserState.getFirstInstallTime()
+                && userState.getEnabledState() == oldUserState.getEnabledState()
+                 && userState.getHarmfulAppWarning().equals(oldUserState.getHarmfulAppWarning())
+                && userState.getInstallReason() == oldUserState.getInstallReason()
+                && userState.getLastDisableAppCaller().equals(
+                        oldUserState.getLastDisableAppCaller())
+                && (userState.getSharedLibraryOverlayPaths() != null
+                ? userState.getSharedLibraryOverlayPaths().equals(
+                        oldUserState.getSharedLibraryOverlayPaths())
+                : oldUserState.getSharedLibraryOverlayPaths() == null)
+                && userState.getSplashScreenTheme().equals(
+                        oldUserState.getSplashScreenTheme())
+                && userState.getUninstallReason() == oldUserState.getUninstallReason();
+    }
+
     private SharedUserSetting createSharedUserSetting(Settings settings, String userName,
             int sharedUserId, int pkgFlags, int pkgPrivateFlags) {
         return settings.addSharedUserLPw(
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 6c72369..a0edb85 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -236,7 +236,7 @@
         testUserState1.setSuspendParams(paramsMap1);
 
         PackageUserStateImpl testUserState2 =
-                new PackageUserStateImpl(testUserState1);
+                new PackageUserStateImpl(null, testUserState1);
         assertThat(testUserState1.equals(testUserState2), is(true));
         testUserState2.setSuspendParams(paramsMap2);
         // Should not be equal since suspendParams maps are different
@@ -250,12 +250,12 @@
         userState1.setDistractionFlags(PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS);
 
         final PackageUserStateImpl copyOfUserState1 =
-                new PackageUserStateImpl(userState1);
+                new PackageUserStateImpl(null, userState1);
         assertThat(userState1.getDistractionFlags(), is(copyOfUserState1.getDistractionFlags()));
         assertThat(userState1.equals(copyOfUserState1), is(true));
 
         final PackageUserStateImpl userState2 =
-                new PackageUserStateImpl(userState1);
+                new PackageUserStateImpl(null, userState1);
         userState2.setDistractionFlags(PackageManager.RESTRICTION_HIDE_NOTIFICATIONS);
         assertThat(userState1.equals(userState2), is(false));
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 687779d..fb3a626 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.window.BackNavigationInfo.typeToString;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -71,7 +72,8 @@
     @Test
     public void backTypeCrossActivityWhenBackToPreviousActivity() {
         Task task = createTopTaskWithActivity();
-        mAtm.setFocusedTask(task.mTaskId, createActivityRecord(task));
+        mAtm.setFocusedTask(task.mTaskId,
+                createAppWindow(task, FIRST_APPLICATION_WINDOW, "window").mActivityRecord);
         BackNavigationInfo backNavigationInfo =
                 mBackNavigationController.startBackNavigation(task, new StubTransaction());
         assertThat(backNavigationInfo).isNotNull();
@@ -85,7 +87,7 @@
     @Test
     public void backNavInfoFullyPopulated() {
         Task task = createTopTaskWithActivity();
-        createActivityRecord(task);
+        createAppWindow(task, FIRST_APPLICATION_WINDOW, "window");
 
         // We need a mock screenshot so
         TaskSnapshotController taskSnapshotController = createMockTaskSnapshotController();
@@ -115,6 +117,7 @@
     private Task createTopTaskWithActivity() {
         Task task = createTask(mDefaultDisplay);
         ActivityRecord record = createActivityRecord(task);
+        createWindow(null, FIRST_APPLICATION_WINDOW, record, "window");
         when(record.mSurfaceControl.isValid()).thenReturn(true);
         mAtm.setFocusedTask(task.mTaskId, record);
         return task;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 65b5cf5..dcaa511 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -80,7 +80,6 @@
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
 import android.os.Binder;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
@@ -231,34 +230,6 @@
     }
 
     @Test
-    public void testTaskOutset() {
-        final Task task = createTask(mDisplayContent);
-        final int taskOutset = 10;
-        spyOn(task);
-        doReturn(taskOutset).when(task).getTaskOutset();
-        doReturn(true).when(task).inMultiWindowMode();
-
-        // Mock the resolved override windowing mode to non-fullscreen
-        final WindowConfiguration windowConfiguration =
-                task.getResolvedOverrideConfiguration().windowConfiguration;
-        spyOn(windowConfiguration);
-        doReturn(WINDOWING_MODE_MULTI_WINDOW)
-                .when(windowConfiguration).getWindowingMode();
-
-        // Prevent adjust task dimensions
-        doNothing().when(task).adjustForMinimalTaskDimensions(any(), any(), any());
-
-        final Rect taskBounds = new Rect(200, 200, 800, 1000);
-        // Update surface position and size by the given bounds.
-        task.setBounds(taskBounds);
-
-        assertEquals(taskBounds.width() + 2 * taskOutset, task.getLastSurfaceSize().x);
-        assertEquals(taskBounds.height() + 2 * taskOutset, task.getLastSurfaceSize().y);
-        assertEquals(taskBounds.left - taskOutset, task.getLastSurfacePosition().x);
-        assertEquals(taskBounds.top - taskOutset, task.getLastSurfacePosition().y);
-    }
-
-    @Test
     public void testActivityAndTaskGetsProperType() {
         final Task task1 = new TaskBuilder(mSupervisor).build();
         ActivityRecord activity1 = createNonAttachedActivityRecord(mDisplayContent);
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 fd523f0..d8c653ce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -49,7 +49,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.view.SurfaceControl;
-import android.view.TransactionCommittedListener;
 import android.window.IDisplayAreaOrganizer;
 import android.window.ITaskOrganizer;
 import android.window.ITransitionPlayer;
@@ -533,8 +532,8 @@
         assertTrue(asyncRotationController.isTargetToken(statusBar.mToken));
 
         final SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class);
-        final ArgumentCaptor<TransactionCommittedListener> listenerCaptor =
-                ArgumentCaptor.forClass(TransactionCommittedListener.class);
+        final ArgumentCaptor<SurfaceControl.TransactionCommittedListener> listenerCaptor =
+                ArgumentCaptor.forClass(SurfaceControl.TransactionCommittedListener.class);
         player.onTransactionReady(startTransaction);
 
         verify(startTransaction).addTransactionCommittedListener(any(), listenerCaptor.capture());
@@ -739,6 +738,9 @@
             }
             from = from.getParent();
         }
+        if (end.asDisplayArea() != null) {
+            end.asDisplayArea().mOrganizer = organizer;
+        }
     }
 
     /** Fill the change map with all the parents of top. Change maps are usually fully populated */
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index c56b614..746f2b5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -21,6 +21,7 @@
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityRecord.State.PAUSED;
@@ -374,12 +375,22 @@
         final ActivityRecord activity = createActivityRecord(mWpc);
         activity.mVisibleRequested = true;
         doReturn(true).when(activity).applyAppSpecificConfig(anyInt(), any());
-        mWpc.updateAppSpecificSettingsForAllActivities(Configuration.UI_MODE_NIGHT_YES,
-                LocaleList.forLanguageTags("en-XA"));
+        mWpc.updateAppSpecificSettingsForAllActivitiesInPackage(DEFAULT_COMPONENT_PACKAGE_NAME,
+                Configuration.UI_MODE_NIGHT_YES, LocaleList.forLanguageTags("en-XA"));
         verify(activity).ensureActivityConfiguration(anyInt(), anyBoolean());
     }
 
     @Test
+    public void testTopActivityUiModeChangeForDifferentPackage_noScheduledConfigChange() {
+        final ActivityRecord activity = createActivityRecord(mWpc);
+        activity.mVisibleRequested = true;
+        mWpc.updateAppSpecificSettingsForAllActivitiesInPackage("com.different.package",
+                Configuration.UI_MODE_NIGHT_YES, LocaleList.forLanguageTags("en-XA"));
+        verify(activity, never()).applyAppSpecificConfig(anyInt(), any());
+        verify(activity, never()).ensureActivityConfiguration(anyInt(), anyBoolean());
+    }
+
+    @Test
     public void testTopActivityDisplayAreaMatchesTopMostActivity_noActivities() {
         assertNull(mWpc.getTopActivityDisplayArea());
     }
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 85b1de5..337e1f9 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -17,6 +17,7 @@
 package com.android.server.usb;
 
 import android.annotation.NonNull;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioSystem;
 import android.media.IAudioService;
 import android.os.RemoteException;
@@ -213,24 +214,25 @@
                 int outputState = (enable && connected) ? 1 : 0;
                 if (outputState != mOutputState) {
                     mOutputState = outputState;
-                    mAudioService.setWiredDeviceConnectionState(device, outputState,
-                                                                alsaCardDeviceString,
-                                                                mDeviceName, TAG);
+                    AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
+                            alsaCardDeviceString, mDeviceName);
+                    mAudioService.setWiredDeviceConnectionState(attributes, outputState, TAG);
                 }
             }
 
             // Input Device
             if (mHasInput) {
-                int device = mIsInputHeadset ? AudioSystem.DEVICE_IN_USB_HEADSET
+                int device = mIsInputHeadset
+                        ? AudioSystem.DEVICE_IN_USB_HEADSET
                         : AudioSystem.DEVICE_IN_USB_DEVICE;
                 boolean connected = isInputJackConnected();
                 Slog.i(TAG, "INPUT JACK connected: " + connected);
                 int inputState = (enable && connected) ? 1 : 0;
                 if (inputState != mInputState) {
                     mInputState = inputState;
-                    mAudioService.setWiredDeviceConnectionState(
-                            device, inputState, alsaCardDeviceString,
-                            mDeviceName, TAG);
+                    AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
+                            alsaCardDeviceString, mDeviceName);
+                    mAudioService.setWiredDeviceConnectionState(attributes, inputState, TAG);
                 }
             }
         } catch (RemoteException e) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index e560f34..2141c794 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -356,13 +356,17 @@
             "android.telecom.extra.INCOMING_CALL_EXTRAS";
 
     /**
-     * Optional extra for {@link #ACTION_INCOMING_CALL} containing a boolean to indicate that the
-     * call has an externally generated ringer. Used by the HfpClientConnectionService when In Band
-     * Ringtone is enabled to prevent two ringers from being generated.
+     * Optional extra for {@link #addNewIncomingCall(PhoneAccountHandle, Bundle)} used to indicate
+     * that a call has an in-band ringtone associated with it.  This is used when the device is
+     * acting as an HFP headset and the Bluetooth stack has received an in-band ringtone from the
+     * the HFP host which must be played instead of any local ringtone the device would otherwise
+     * have generated.
+     *
      * @hide
      */
-    public static final String EXTRA_CALL_EXTERNAL_RINGER =
-            "android.telecom.extra.CALL_EXTERNAL_RINGER";
+    @SystemApi
+    public static final String EXTRA_CALL_HAS_IN_BAND_RINGTONE =
+            "android.telecom.extra.CALL_HAS_IN_BAND_RINGTONE";
 
     /**
      * Optional extra for {@link android.content.Intent#ACTION_CALL} and
@@ -1489,9 +1493,14 @@
      * when placing calls. The user may still need to enable the {@link PhoneAccount} within
      * the phone app settings before the account is usable.
      * <p>
+     * Note: Each package is limited to 10 {@link PhoneAccount} registrations.
+     * <p>
      * A {@link SecurityException} will be thrown if an app tries to register a
      * {@link PhoneAccountHandle} where the package name specified within
      * {@link PhoneAccountHandle#getComponentName()} does not match the package name of the app.
+     * <p>
+     * A {@link IllegalArgumentException} will be thrown if an app tries to register a
+     * {@link PhoneAccount} when the upper bound limit, 10, has already been reached.
      *
      * @param account The complete {@link PhoneAccount}.
      */
diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index 184e154..30ed7c2 100644
--- a/telephony/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
@@ -257,6 +257,13 @@
             "android.service.euicc.extra.RESOLUTION_CARD_ID";
 
     /**
+     * Intent extra set for resolution requests containing an int indicating the subscription id
+     * to be enabled.
+     */
+    public static final String EXTRA_RESOLUTION_SUBSCRIPTION_ID =
+            "android.service.euicc.extra.RESOLUTION_SUBSCRIPTION_ID";
+
+    /**
      * Intent extra set for resolution requests containing an int indicating the current port index.
      */
     public static final String EXTRA_RESOLUTION_PORT_INDEX =
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index e88106c..86b98f1 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -127,7 +127,9 @@
             ApnSetting.TYPE_EMERGENCY,
             ApnSetting.TYPE_MCX,
             ApnSetting.TYPE_XCAP,
-            // ApnSetting.TYPE_ENTERPRISE
+            ApnSetting.TYPE_BIP,
+            ApnSetting.TYPE_VSIM,
+            ApnSetting.TYPE_ENTERPRISE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ApnType {
@@ -707,6 +709,9 @@
             NetworkCapabilities.NET_CAPABILITY_VSIM,
             NetworkCapabilities.NET_CAPABILITY_BIP,
             NetworkCapabilities.NET_CAPABILITY_HEAD_UNIT,
+            NetworkCapabilities.NET_CAPABILITY_MMTEL,
+            NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY,
+            NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH
     })
     public @interface NetCapability { }
 
@@ -721,4 +726,16 @@
             NetworkAgent.VALIDATION_STATUS_NOT_VALID
     })
     public @interface ValidationStatus {}
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "NET_CAPABILITY_ENTERPRISE_SUB_LEVEL" }, value = {
+            NetworkCapabilities.NET_ENTERPRISE_ID_1,
+            NetworkCapabilities.NET_ENTERPRISE_ID_2,
+            NetworkCapabilities.NET_ENTERPRISE_ID_3,
+            NetworkCapabilities.NET_ENTERPRISE_ID_4,
+            NetworkCapabilities.NET_ENTERPRISE_ID_5
+    })
+
+    public @interface EnterpriseId {}
 }
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index 4978692..82333a4 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -46,16 +46,17 @@
     private final int keyType;
     //Date-Time in UTC when the key will expire.
     private final Date expirationTime;
+    private final int carrierId;
 
     /** @hide */
     public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
-                              byte[] key, Date expirationTime) {
-        this(mcc, mnc, keyType, keyIdentifier, makeKeyObject(key), expirationTime);
+            byte[] key, Date expirationTime, int carrierId) {
+        this(mcc, mnc, keyType, keyIdentifier, makeKeyObject(key), expirationTime, carrierId);
     }
 
     /** @hide */
     public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
-                              PublicKey publicKey, Date expirationTime) {
+            PublicKey publicKey, Date expirationTime, int carrierId) {
         // todo need to validate that ImsiEncryptionInfo is being created with the correct params.
         //      Including validating that the public key is in "X.509" format. This will be done in
         //      a subsequent CL.
@@ -65,6 +66,7 @@
         this.publicKey = publicKey;
         this.keyIdentifier = keyIdentifier;
         this.expirationTime = expirationTime;
+        this.carrierId = carrierId;
     }
 
     /** @hide */
@@ -78,6 +80,7 @@
         keyIdentifier = in.readString();
         keyType = in.readInt();
         expirationTime = new Date(in.readLong());
+        carrierId = in.readInt();
     }
 
     /** @hide */
@@ -90,6 +93,11 @@
         return this.mcc;
     }
 
+    /** @hide */
+    public int getCarrierId() {
+        return carrierId;
+    }
+
     /**
      * Returns key identifier, a string that helps the authentication server to locate the
      * private key to decrypt the permanent identity, or {@code null} when uavailable.
@@ -157,6 +165,7 @@
         dest.writeString(keyIdentifier);
         dest.writeInt(keyType);
         dest.writeLong(expirationTime.getTime());
+        dest.writeInt(carrierId);
     }
 
     @Override
@@ -164,10 +173,11 @@
         return "[ImsiEncryptionInfo "
                 + "mcc=" + mcc
                 + " mnc=" + mnc
-                + " publicKey=" + publicKey
+                + ", publicKey=" + publicKey
                 + ", keyIdentifier=" + keyIdentifier
                 + ", keyType=" + keyType
                 + ", expirationTime=" + expirationTime
+                + ", carrier_id=" + carrierId
                 + "]";
     }
 }
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 5a12865..e0145e6 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -79,7 +79,7 @@
     public static final int ENCODING_8BIT = 2;
     public static final int ENCODING_16BIT = 3;
     /**
-     * @hide This value is not defined in global standard. Only in Korea, this is used.
+     * This value is not defined in global standard. Only in Korea, this is used.
      */
     public static final int ENCODING_KSC5601 = 4;
 
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 250e55c..0aaafef 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2863,10 +2863,43 @@
      *             outlined above.
      * @throws IllegalArgumentException if plans don't meet the requirements
      *             defined in {@link SubscriptionPlan}.
+     * @deprecated use {@link #setSubscriptionPlans(int, List, long)} instead.
      */
+    @Deprecated
     public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans) {
+        setSubscriptionPlans(subId, plans, 0);
+    }
+
+    /**
+     * Set the description of the billing relationship plan between a carrier
+     * and a specific subscriber.
+     * <p>
+     * This method is only accessible to the following narrow set of apps:
+     * <ul>
+     * <li>The carrier app for this subscriberId, as determined by
+     * {@link TelephonyManager#hasCarrierPrivileges()}.
+     * <li>The carrier app explicitly delegated access through
+     * {@link CarrierConfigManager#KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING}.
+     * </ul>
+     *
+     * @param subId the subscriber this relationship applies to. An empty list
+     *            may be sent to clear any existing plans.
+     * @param plans the list of plans. The first plan is always the primary and
+     *            most important plan. Any additional plans are secondary and
+     *            may not be displayed or used by decision making logic.
+     * @param expirationDurationMillis the duration after which the subscription plans
+     *            will be automatically cleared, or {@code 0} to leave the plans until
+     *            explicitly cleared, or the next reboot, whichever happens first.
+     * @throws SecurityException if the caller doesn't meet the requirements
+     *             outlined above.
+     * @throws IllegalArgumentException if plans don't meet the requirements
+     *             defined in {@link SubscriptionPlan}.
+     */
+    public void setSubscriptionPlans(int subId, @NonNull List<SubscriptionPlan> plans,
+            @DurationMillisLong long expirationDurationMillis) {
         getNetworkPolicyManager().setSubscriptionPlans(subId,
-                plans.toArray(new SubscriptionPlan[plans.size()]), mContext.getOpPackageName());
+                plans.toArray(new SubscriptionPlan[0]), expirationDurationMillis,
+                mContext.getOpPackageName());
     }
 
     /**
@@ -2885,17 +2918,17 @@
      * @param subId the subscriber this override applies to.
      * @param overrideUnmetered set if the billing relationship should be
      *            considered unmetered.
-     * @param timeoutMillis the timeout after which the requested override will
-     *            be automatically cleared, or {@code 0} to leave in the
+     * @param expirationDurationMillis the duration after which the requested override
+     *            will be automatically cleared, or {@code 0} to leave in the
      *            requested state until explicitly cleared, or the next reboot,
      *            whichever happens first.
      * @throws SecurityException if the caller doesn't meet the requirements
      *            outlined above.
      */
     public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered,
-            @DurationMillisLong long timeoutMillis) {
+            @DurationMillisLong long expirationDurationMillis) {
         setSubscriptionOverrideUnmetered(subId, overrideUnmetered,
-                TelephonyManager.getAllNetworkTypes(), timeoutMillis);
+                TelephonyManager.getAllNetworkTypes(), expirationDurationMillis);
     }
 
     /**
@@ -2917,8 +2950,8 @@
      * @param networkTypes the network types this override applies to. If no
      *            network types are specified, override values will be ignored.
      *            {@see TelephonyManager#getAllNetworkTypes()}
-     * @param timeoutMillis the timeout after which the requested override will
-     *            be automatically cleared, or {@code 0} to leave in the
+     * @param expirationDurationMillis the duration after which the requested override
+     *            will be automatically cleared, or {@code 0} to leave in the
      *            requested state until explicitly cleared, or the next reboot,
      *            whichever happens first.
      * @throws SecurityException if the caller doesn't meet the requirements
@@ -2926,10 +2959,10 @@
      */
     public void setSubscriptionOverrideUnmetered(int subId, boolean overrideUnmetered,
             @NonNull @Annotation.NetworkType int[] networkTypes,
-            @DurationMillisLong long timeoutMillis) {
+            @DurationMillisLong long expirationDurationMillis) {
         final int overrideValue = overrideUnmetered ? SUBSCRIPTION_OVERRIDE_UNMETERED : 0;
         getNetworkPolicyManager().setSubscriptionOverride(subId, SUBSCRIPTION_OVERRIDE_UNMETERED,
-                overrideValue, networkTypes, timeoutMillis, mContext.getOpPackageName());
+                overrideValue, networkTypes, expirationDurationMillis, mContext.getOpPackageName());
     }
 
     /**
@@ -2949,17 +2982,17 @@
      * @param subId the subscriber this override applies to.
      * @param overrideCongested set if the subscription should be considered
      *            congested.
-     * @param timeoutMillis the timeout after which the requested override will
-     *            be automatically cleared, or {@code 0} to leave in the
+     * @param expirationDurationMillis the duration after which the requested override
+     *            will be automatically cleared, or {@code 0} to leave in the
      *            requested state until explicitly cleared, or the next reboot,
      *            whichever happens first.
      * @throws SecurityException if the caller doesn't meet the requirements
      *            outlined above.
      */
     public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
-            @DurationMillisLong long timeoutMillis) {
+            @DurationMillisLong long expirationDurationMillis) {
         setSubscriptionOverrideCongested(subId, overrideCongested,
-                TelephonyManager.getAllNetworkTypes(), timeoutMillis);
+                TelephonyManager.getAllNetworkTypes(), expirationDurationMillis);
     }
 
     /**
@@ -2982,8 +3015,8 @@
      * @param networkTypes the network types this override applies to. If no
      *            network types are specified, override values will be ignored.
      *            {@see TelephonyManager#getAllNetworkTypes()}
-     * @param timeoutMillis the timeout after which the requested override will
-     *            be automatically cleared, or {@code 0} to leave in the
+     * @param expirationDurationMillis the duration after which the requested override
+     *            will be automatically cleared, or {@code 0} to leave in the
      *            requested state until explicitly cleared, or the next reboot,
      *            whichever happens first.
      * @throws SecurityException if the caller doesn't meet the requirements
@@ -2991,10 +3024,10 @@
      */
     public void setSubscriptionOverrideCongested(int subId, boolean overrideCongested,
             @NonNull @Annotation.NetworkType int[] networkTypes,
-            @DurationMillisLong long timeoutMillis) {
+            @DurationMillisLong long expirationDurationMillis) {
         final int overrideValue = overrideCongested ? SUBSCRIPTION_OVERRIDE_CONGESTED : 0;
         getNetworkPolicyManager().setSubscriptionOverride(subId, SUBSCRIPTION_OVERRIDE_CONGESTED,
-                overrideValue, networkTypes, timeoutMillis, mContext.getOpPackageName());
+                overrideValue, networkTypes, expirationDurationMillis, mContext.getOpPackageName());
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index baccb26..ba1a6ed 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9199,7 +9199,8 @@
      * @param allowedNetworkTypes The bitmask of allowed network types.
      * @return true on success; false on any failure.
      * @hide
-     * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead.
+     * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead with reason
+     * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER}.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@@ -9233,10 +9234,7 @@
 
     /**
      * To indicate allowed network type change is requested by user.
-     *
-     * @hide
      */
-    @SystemApi
     public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0;
 
     /**
@@ -9255,10 +9253,7 @@
      * Carrier configuration won't affect the settings configured through
      * other reasons and will result in allowing network types that are in both
      * configurations (i.e intersection of both sets).
-     *
-     * @hide
      */
-    @SystemApi
     public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2;
 
     /**
@@ -9272,35 +9267,23 @@
     /**
      * Set the allowed network types of the device and provide the reason triggering the allowed
      * network change.
+     * <p>Requires permission: android.Manifest.MODIFY_PHONE_STATE or
+     * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
      * This can be called for following reasons
      * <ol>
      * <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER}
-     * <li>Allowed network types control by power manager
-     * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER}
      * <li>Allowed network types control by carrier {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER}
-     * <li>Allowed network types control by the user-controlled "Allow 2G" toggle
-     * {@link #ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}
      * </ol>
      * This API will result in allowing an intersection of allowed network types for all reasons,
      * including the configuration done through other reasons.
      *
-     * The functionality of this API with the parameter
-     * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} is the same as the API
-     * {@link TelephonyManager#setAllowedNetworkTypes}. Use this API instead of
-     * {@link TelephonyManager#setAllowedNetworkTypes}.
-     * <p>
-     * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}
-     * ({@link TelephonyManager#CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK}) returns true, then
-     * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise,
-     * setPreferredNetworkTypesBitmap is used instead.
-     *
      * @param reason the reason the allowed network type change is taking place
-     * @param allowedNetworkTypes The bitmask of allowed network types.
+     * @param allowedNetworkTypes The bitmask of allowed network type
      * @throws IllegalStateException if the Telephony process is not currently available.
      * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
-     * @hide
+     * @throws SecurityException if the caller does not have the required privileges
      */
-    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     @RequiresFeature(
             enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
@@ -9330,18 +9313,19 @@
      *
      * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a
      * specific reason.
+     * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE or
+     * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param reason the reason the allowed network type change is taking place
      * @return the allowed network type bitmask
      * @throws IllegalStateException    if the Telephony process is not currently available.
      * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
-     * @hide
+     * @throws SecurityException if the caller does not have the required permission/privileges
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @RequiresFeature(
             enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported",
             value = TelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK)
-    @SystemApi
     public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
             @AllowedNetworkTypesReason int reason) {
         if (!isValidAllowedNetworkTypesReason(reason)) {
@@ -13560,127 +13544,88 @@
     // 2G
     /**
      * network type bitmask unknown.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L;
     /**
      * network type bitmask indicating the support of radio tech GSM.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_GSM = (1 << (NETWORK_TYPE_GSM -1));
     /**
      * network type bitmask indicating the support of radio tech GPRS.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_GPRS = (1 << (NETWORK_TYPE_GPRS -1));
     /**
      * network type bitmask indicating the support of radio tech EDGE.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EDGE = (1 << (NETWORK_TYPE_EDGE -1));
     /**
      * network type bitmask indicating the support of radio tech CDMA(IS95A/IS95B).
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_CDMA = (1 << (NETWORK_TYPE_CDMA -1));
     /**
      * network type bitmask indicating the support of radio tech 1xRTT.
-     * @hide
      */
-    @SystemApi
+    @SuppressLint("AllUpper")
     public static final long NETWORK_TYPE_BITMASK_1xRTT = (1 << (NETWORK_TYPE_1xRTT - 1));
     // 3G
     /**
      * network type bitmask indicating the support of radio tech EVDO 0.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EVDO_0 = (1 << (NETWORK_TYPE_EVDO_0 -1));
     /**
      * network type bitmask indicating the support of radio tech EVDO A.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EVDO_A = (1 << (NETWORK_TYPE_EVDO_A - 1));
     /**
      * network type bitmask indicating the support of radio tech EVDO B.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EVDO_B = (1 << (NETWORK_TYPE_EVDO_B -1));
     /**
      * network type bitmask indicating the support of radio tech EHRPD.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_EHRPD = (1 << (NETWORK_TYPE_EHRPD -1));
     /**
      * network type bitmask indicating the support of radio tech HSUPA.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_HSUPA = (1 << (NETWORK_TYPE_HSUPA -1));
     /**
      * network type bitmask indicating the support of radio tech HSDPA.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_HSDPA = (1 << (NETWORK_TYPE_HSDPA -1));
     /**
      * network type bitmask indicating the support of radio tech HSPA.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_HSPA = (1 << (NETWORK_TYPE_HSPA -1));
     /**
      * network type bitmask indicating the support of radio tech HSPAP.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_HSPAP = (1 << (NETWORK_TYPE_HSPAP -1));
     /**
      * network type bitmask indicating the support of radio tech UMTS.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_UMTS = (1 << (NETWORK_TYPE_UMTS -1));
     /**
      * network type bitmask indicating the support of radio tech TD_SCDMA.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = (1 << (NETWORK_TYPE_TD_SCDMA -1));
     // 4G
     /**
      * network type bitmask indicating the support of radio tech LTE.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_LTE = (1 << (NETWORK_TYPE_LTE -1));
     /**
      * network type bitmask indicating the support of radio tech LTE CA (carrier aggregation).
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_LTE_CA = (1 << (NETWORK_TYPE_LTE_CA -1));
 
     /**
      * network type bitmask indicating the support of radio tech NR(New Radio) 5G.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_NR = (1 << (NETWORK_TYPE_NR -1));
 
     /**
      * network type bitmask indicating the support of radio tech IWLAN.
-     * @hide
      */
-    @SystemApi
     public static final long NETWORK_TYPE_BITMASK_IWLAN = (1 << (NETWORK_TYPE_IWLAN -1));
 
     /** @hide */
@@ -13735,12 +13680,11 @@
     /**
      * @return Modem supported radio access family bitmask
      *
-     * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or
+     * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE or
      * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
-     * @hide
+     *
+     * @throws SecurityException if the caller does not have the required permission
      */
-    @SystemApi
-    @TestApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public @NetworkTypeBitMask long getSupportedRadioAccessFamily() {
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index a166a5d..fa1bae4 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -26,10 +26,10 @@
 import android.net.NetworkCapabilities;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.NetCapability;
 import android.telephony.TelephonyManager;
 import android.telephony.TelephonyManager.NetworkTypeBitMask;
+import android.telephony.data.ApnSetting.ApnType;
 import android.telephony.data.ApnSetting.AuthType;
 import android.text.TextUtils;
 
@@ -245,8 +245,7 @@
      * @return The supported APN types bitmask.
      * @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getApnTypeBitmask()} instead.
      */
-    @Deprecated
-    public @ApnType int getSupportedApnTypesBitmask() {
+    @Deprecated public @ApnType int getSupportedApnTypesBitmask() {
         if (mApnSetting != null) {
             return mApnSetting.getApnTypeBitmask();
         }
@@ -425,6 +424,12 @@
                 return ApnSetting.TYPE_MCX;
             case NetworkCapabilities.NET_CAPABILITY_IA:
                 return ApnSetting.TYPE_IA;
+            case NetworkCapabilities.NET_CAPABILITY_BIP:
+                return ApnSetting.TYPE_BIP;
+            case NetworkCapabilities.NET_CAPABILITY_VSIM:
+                return ApnSetting.TYPE_VSIM;
+            case NetworkCapabilities.NET_CAPABILITY_ENTERPRISE:
+                return ApnSetting.TYPE_ENTERPRISE;
             default:
                 return ApnSetting.TYPE_NONE;
         }
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 1ff6ec1..ec73471 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -261,9 +261,10 @@
     }
 
     /**
-     * Unthrottles the APN on the current transport.  There is no matching "APN throttle" method.
-     * Instead, the APN is throttled when {@link IDataService#setupDataCall} fails within
-     * the time specified by {@link DataCallResponse#getRetryDurationMillis}.
+     * Unthrottles the APN on the current transport.
+     * The APN is throttled when {@link IDataService#setupDataCall} fails within
+     * the time specified by {@link DataCallResponse#getRetryDurationMillis} and will remain
+     * throttled until this method is called.
      * <p/>
      * see: {@link DataCallResponse#getRetryDurationMillis}
      *
@@ -284,9 +285,9 @@
 
     /**
      * Unthrottles the DataProfile on the current transport.
-     * There is no matching "DataProfile throttle" method.
-     * Instead, the DataProfile is throttled when {@link IDataService#setupDataCall} fails within
-     * the time specified by {@link DataCallResponse#getRetryDurationMillis}.
+     * The DataProfile is throttled when {@link IDataService#setupDataCall} fails within
+     * the time specified by {@link DataCallResponse#getRetryDurationMillis} and will remain
+     * throttled until this method is called.
      * <p/>
      * see: {@link DataCallResponse#getRetryDurationMillis}
      *
diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.java b/telephony/java/android/telephony/data/TrafficDescriptor.java
index 2178fc1..66dcf8f 100644
--- a/telephony/java/android/telephony/data/TrafficDescriptor.java
+++ b/telephony/java/android/telephony/data/TrafficDescriptor.java
@@ -21,8 +21,13 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
 import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * A traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2. It is used for UE Route Selection
@@ -31,24 +36,215 @@
  * not specify the end point to be used for the data call.
  */
 public final class TrafficDescriptor implements Parcelable {
+    /**
+     * The OS/App id
+     *
+     * @hide
+     */
+    public static final class OsAppId {
+        /**
+         * OSId for "Android", using UUID version 5 with namespace ISO OSI.
+         * Prepended to the OsAppId in TrafficDescriptor to use for URSP matching.
+         */
+        public static final UUID ANDROID_OS_ID =
+                UUID.fromString("97a498e3-fc92-5c94-8986-0333d06e4e47");
+
+        /**
+         * Allowed app ids.
+         */
+        // The following app ids are the only apps id Android supports. OEMs or vendors are
+        // prohibited to modify/extend the allowed list, especially passing the real package name to
+        // the network.
+        private static final Set<String> ALLOWED_APP_IDS = Set.of(
+                "ENTERPRISE", "PRIORITIZE_LATENCY", "PRIORITIZE_BANDWIDTH", "CBS"
+        );
+
+        /** OS id in UUID format. */
+        private final @NonNull UUID mOsId;
+
+        /**
+         * App id in string format. Note that Android will not allow use specific app id. This must
+         * be a category/capability identifier.
+         */
+        private final @NonNull String mAppId;
+
+        /**
+         * The differentiator when multiple traffic descriptor has the same OS and app id. Must be
+         * greater than 1.
+         */
+        private final int mDifferentiator;
+
+        /**
+         * Constructor
+         *
+         * @param osId OS id in UUID format.
+         * @param appId App id in string format. Note that Android will not allow use specific app
+         * id. This must be a category/capability identifier.
+         */
+        public OsAppId(@NonNull UUID osId, @NonNull String appId) {
+            this(osId, appId, 1);
+        }
+
+        /**
+         * Constructor
+         *
+         * @param osId OS id in UUID format.
+         * @param appId App id in string format. Note that Android will not allow use specific app
+         * id. This must be a category/capability identifier.
+         * @param differentiator The differentiator when multiple traffic descriptor has the same
+         * OS and app id. Must be greater than 0.
+         */
+        public OsAppId(@NonNull UUID osId, @NonNull String appId, int differentiator) {
+            Objects.requireNonNull(osId);
+            Objects.requireNonNull(appId);
+            if (differentiator < 1) {
+                throw new IllegalArgumentException("Invalid differentiator " + differentiator);
+            }
+
+            mOsId = osId;
+            mAppId = appId;
+            mDifferentiator = differentiator;
+        }
+
+        /**
+         * Constructor from raw byte array.
+         *
+         * @param rawOsAppId The raw OS/App id.
+         */
+        public OsAppId(@NonNull byte[] rawOsAppId) {
+            try {
+                ByteBuffer bb = ByteBuffer.wrap(rawOsAppId);
+                // OS id is the first 16 bytes.
+                mOsId = new UUID(bb.getLong(), bb.getLong());
+                // App id length is 1 byte.
+                int appIdLen = bb.get();
+                // The remaining is the app id + differentiator.
+                byte[] appIdAndDifferentiator = new byte[appIdLen];
+                bb.get(appIdAndDifferentiator, 0, appIdLen);
+                // Extract trailing numbers, for example, "ENTERPRISE", "ENTERPRISE3".
+                String appIdAndDifferentiatorStr = new String(appIdAndDifferentiator);
+                Pattern pattern = Pattern.compile("[^0-9]+([0-9]+)$");
+                Matcher matcher = pattern.matcher(new String(appIdAndDifferentiator));
+                if (matcher.find()) {
+                    mDifferentiator = Integer.parseInt(matcher.group(1));
+                    mAppId = appIdAndDifferentiatorStr.replace(matcher.group(1), "");
+                } else {
+                    mDifferentiator = 1;
+                    mAppId = appIdAndDifferentiatorStr;
+                }
+            } catch (Exception e) {
+                throw new IllegalArgumentException("Failed to decode " + (rawOsAppId != null
+                        ? new BigInteger(1, rawOsAppId).toString(16) : null));
+            }
+        }
+
+        /**
+         * @return The OS id in UUID format.
+         */
+        public @NonNull UUID getOsId() {
+            return mOsId;
+        }
+
+        /**
+         * @return App id in string format. Note that Android will not allow use specific app id.
+         * This must be a category/capability identifier.
+         */
+        public @NonNull String getAppId() {
+            return mAppId;
+        }
+
+        /**
+         * @return The differentiator when multiple traffic descriptor has the same OS and app id.
+         * Must be greater than 1.
+         */
+        public int getDifferentiator() {
+            return mDifferentiator;
+        }
+
+        /**
+         * @return OS/App id in raw byte format.
+         */
+        public @NonNull byte[] getBytes() {
+            byte[] osAppId = (mAppId + (mDifferentiator > 1 ? mDifferentiator : "")).getBytes();
+            // 16 bytes for UUID, 1 byte for length of osAppId, and up to 255 bytes for osAppId
+            ByteBuffer bb = ByteBuffer.allocate(16 + 1 + osAppId.length);
+            bb.putLong(mOsId.getMostSignificantBits());
+            bb.putLong(mOsId.getLeastSignificantBits());
+            bb.put((byte) osAppId.length);
+            bb.put(osAppId);
+            return bb.array();
+        }
+
+        @Override
+        public String toString() {
+            return "[OsAppId: OS=" + mOsId + ", App=" + mAppId + ", differentiator="
+                    + mDifferentiator + ", raw="
+                    + new BigInteger(1, getBytes()).toString(16) + "]";
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            OsAppId osAppId = (OsAppId) o;
+            return mDifferentiator == osAppId.mDifferentiator && mOsId.equals(osAppId.mOsId)
+                    && mAppId.equals(osAppId.mAppId);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mOsId, mAppId, mDifferentiator);
+        }
+    }
+
     private final String mDnn;
-    private final byte[] mOsAppId;
+    private final OsAppId mOsAppId;
 
     private TrafficDescriptor(@NonNull Parcel in) {
         mDnn = in.readString();
-        mOsAppId = in.createByteArray();
+        byte[] osAppIdBytes = in.createByteArray();
+        OsAppId osAppId = null;
+        if (osAppIdBytes != null) {
+            osAppId = new OsAppId(osAppIdBytes);
+        }
+        mOsAppId = osAppId;
+
+        enforceAllowedIds();
     }
 
     /**
      * Create a traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2
      * @param dnn optional DNN, which must be used for traffic matching, if present
-     * @param osAppId OsId + osAppId of the traffic descriptor
+     * @param osAppIdRawBytes Raw bytes of OsId + osAppId of the traffic descriptor
      *
      * @hide
      */
-    public TrafficDescriptor(String dnn, byte[] osAppId) {
+    public TrafficDescriptor(String dnn, @Nullable byte[] osAppIdRawBytes) {
         mDnn = dnn;
+        OsAppId osAppId = null;
+        if (osAppIdRawBytes != null) {
+            osAppId = new OsAppId(osAppIdRawBytes);
+        }
         mOsAppId = osAppId;
+
+        enforceAllowedIds();
+    }
+
+    /**
+     * Enforce the OS id and app id are in the allowed list.
+     *
+     * @throws IllegalArgumentException if ids are not allowed.
+     */
+    private void enforceAllowedIds() {
+        if (mOsAppId != null && !mOsAppId.getOsId().equals(OsAppId.ANDROID_OS_ID)) {
+            throw new IllegalArgumentException("OS id " + mOsAppId.getOsId() + " does not match "
+                    + OsAppId.ANDROID_OS_ID);
+        }
+
+        if (mOsAppId != null && !OsAppId.ALLOWED_APP_IDS.contains(mOsAppId.getAppId())) {
+            throw new IllegalArgumentException("Illegal app id " + mOsAppId.getAppId()
+                    + ". Only allowing one of the following " + OsAppId.ALLOWED_APP_IDS);
+        }
     }
 
     /**
@@ -61,13 +257,13 @@
     }
 
     /**
-     * OsAppId is the app id as defined in 3GPP TS 24.526 Section 5.2, and it identifies a traffic
-     * category. It includes the OS Id component of the field as defined in the specs.
-     * @return the OS App ID of this traffic descriptor if one is included by the network, null
-     * otherwise.
+     * OsAppId identifies a broader traffic category. Although it names Os/App id, it only includes
+     * OS version with a general/broader category id used as app id.
+     *
+     * @return The id in byte format. {@code null} if not available.
      */
     public @Nullable byte[] getOsAppId() {
-        return mOsAppId;
+        return mOsAppId != null ? mOsAppId.getBytes() : null;
     }
 
     @Override
@@ -77,13 +273,13 @@
 
     @NonNull @Override
     public String toString() {
-        return "TrafficDescriptor={mDnn=" + mDnn + ", mOsAppId=" + mOsAppId + "}";
+        return "TrafficDescriptor={mDnn=" + mDnn + ", " + mOsAppId + "}";
     }
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mDnn);
-        dest.writeByteArray(mOsAppId);
+        dest.writeByteArray(mOsAppId != null ? mOsAppId.getBytes() : null);
     }
 
     public static final @NonNull Parcelable.Creator<TrafficDescriptor> CREATOR =
@@ -104,7 +300,7 @@
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         TrafficDescriptor that = (TrafficDescriptor) o;
-        return Objects.equals(mDnn, that.mDnn) && Arrays.equals(mOsAppId, that.mOsAppId);
+        return Objects.equals(mDnn, that.mDnn) && Objects.equals(mOsAppId, that.mOsAppId);
     }
 
     @Override
@@ -148,7 +344,7 @@
         }
 
         /**
-         * Set the OS App ID (including OS Id as defind in the specs).
+         * Set the OS App ID (including OS Id as defined in the specs).
          *
          * @return The same instance of the builder.
          */
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 566c725..98d13e8 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -26,8 +26,16 @@
         <option name="shell-timeout" value="6600s" />
         <option name="test-timeout" value="6600s" />
         <option name="hidden-api-checks" value="false" />
+        <option name="device-listeners"
+                value="com.android.server.wm.flicker.TraceFileReadyListener" />
     </test>
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+        <option name="pull-pattern-keys" value="(\w)+\.winscope" />
+        <option name="pull-pattern-keys" value="(\w)+\.mp4" />
+        <option name="collect-on-run-ended-only" value="false" />
+        <option name="clean-up" value="true" />
+    </metrics_collector>
+    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
         <option name="directory-keys" value="/sdcard/flicker" />
         <option name="collect-on-run-ended-only" value="true" />
         <option name="clean-up" value="true" />
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index 8fe0029..b66c45c7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -19,11 +19,13 @@
 import android.app.Instrumentation
 import android.support.test.launcherhelper.ILauncherStrategy
 import android.support.test.launcherhelper.LauncherStrategyFactory
+import android.view.Display
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
 import com.android.server.wm.traces.parser.toFlickerComponent
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 
@@ -36,6 +38,10 @@
         .getInstance(instr)
         .launcherStrategy
 ) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+    private val secondActivityComponent =
+        ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent()
+
     fun openSecondActivity(device: UiDevice, wmHelper: WindowManagerStateHelper) {
         val launchActivityButton = By.res(getPackage(), LAUNCH_SECOND_ACTIVITY)
         val button = device.wait(Until.findObject(launchActivityButton), FIND_TIMEOUT)
@@ -47,8 +53,11 @@
         button.click()
 
         device.wait(Until.gone(launchActivityButton), FIND_TIMEOUT)
-        wmHelper.waitForAppTransitionIdle()
-        wmHelper.waitForFullScreenApp(component)
+        wmHelper.waitForFullScreenApp(secondActivityComponent)
+        wmHelper.waitFor(
+            WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY),
+            WindowManagerConditionsFactory.hasLayersAnimating().negate()
+        )
     }
 
     companion object {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index 648353e..195af58 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -70,7 +70,7 @@
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
             setup {
-                eachRun {
+                test {
                     testApp.launchViaIntent(wmHelper)
                     wmHelper.waitForFullScreenApp(testApp.component)
                 }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt
index d3ad9e8..3af5450 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapTransitionView.kt
@@ -41,7 +41,7 @@
             ImageDecoder.createSource(context.resources, R.drawable.very_large_photo))
     private val mShaderA = BitmapShader(mImageA, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
     private val mShaderB = BitmapShader(mImageB, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
-    private val mShader = RuntimeShader(AGSL, false)
+    private val mShader = RuntimeShader(AGSL)
     private var mCurrentProgress = -1f
     private var mForwardProgress = true
     private var mCurrentAnimator = ValueAnimator.ofFloat(-1f, 1f)
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 65d168b..fafe60b 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -83,7 +83,7 @@
             mBlendPaint = new Paint();
             mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));
 
-            mRuntimeShader = new RuntimeShader(sSkSL, false);
+            mRuntimeShader = new RuntimeShader(sSkSL);
             mRuntimeShader.setFloatUniform("param1", mShaderParam1);
             mRuntimeShader.setInputShader("bitmapShader", new BitmapShader(mBitmap1,
                                                                            Shader.TileMode.CLAMP,
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
index 06280d2..3c71b96 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RenderEffectViewActivity.kt
@@ -30,7 +30,7 @@
 
 class RenderEffectViewActivity : Activity() {
 
-    private val mDropsShader = RuntimeShader(dropsAGSL, false)
+    private val mDropsShader = RuntimeShader(dropsAGSL)
     private var mDropsAnimator = ValueAnimator.ofFloat(0f, 1f)
     private var mStartTime = System.currentTimeMillis()
     private lateinit var mScratchesImage: Bitmap
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
index 73c4b8a..b78907c 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RippleActivity.java
@@ -109,7 +109,7 @@
             p.setColor(mColor);
             mPaint = CanvasProperty.createPaint(p);
 
-            mRuntimeShader = new RuntimeShader(sSkSL, false);
+            mRuntimeShader = new RuntimeShader(sSkSL);
             mRuntimeShader.setFloatUniform("in_maxRadius", MAX_RADIUS);
         }
 
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
index 12e338c..2990c9e 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/StretchShaderActivity.java
@@ -69,7 +69,7 @@
         linearLayout.setOrientation(LinearLayout.VERTICAL);
 
         mBitmap = ((BitmapDrawable) getDrawable(R.drawable.sunset1)).getBitmap();
-        mRuntimeShader = new RuntimeShader(SKSL, false);
+        mRuntimeShader = new RuntimeShader(SKSL);
 
         BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP,
                 Shader.TileMode.CLAMP);
diff --git a/tests/SilkFX/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml
index c30d761..21256d8 100644
--- a/tests/SilkFX/AndroidManifest.xml
+++ b/tests/SilkFX/AndroidManifest.xml
@@ -20,17 +20,20 @@
     <uses-sdk android:minSdkVersion="30"/>
 
     <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
     <application android:label="SilkFX"
          android:theme="@android:style/Theme.Material">
 
         <activity android:name=".Main"
              android:label="SilkFX Demos"
+             android:banner="@drawable/background1"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.DEFAULT"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
+                <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
             </intent-filter>
         </activity>
 
@@ -41,13 +44,16 @@
 
         <activity android:name=".materials.GlassActivity"
             android:label="Glass Examples"
-            android:banner="@drawable/background1"
             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
             </intent-filter>
         </activity>
 
+        <activity android:name=".materials.BackgroundBlurActivity"
+            android:theme="@style/Theme.BackgroundBlurTheme"
+            android:exported="true">
+        </activity>
+
     </application>
 </manifest>
diff --git a/services/tests/servicestests/res/xml/test_dream_metadata.xml b/tests/SilkFX/res/drawable/background_blur_drawable.xml
similarity index 75%
rename from services/tests/servicestests/res/xml/test_dream_metadata.xml
rename to tests/SilkFX/res/drawable/background_blur_drawable.xml
index aa054f1..173ca99 100644
--- a/services/tests/servicestests/res/xml/test_dream_metadata.xml
+++ b/tests/SilkFX/res/drawable/background_blur_drawable.xml
@@ -13,7 +13,8 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<dream xmlns:android="http://schemas.android.com/apk/res/android"
-       android:settingsActivity="com.android.server.dreams/.TestDreamSettingsActivity"
-       android:showClockAndComplications="false" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+           android:shape="rectangle">
+    <solid android:color="#20FFFFFF"/>
+    <corners android:radius="10dp"/>
+</shape>
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more_ripple.xml b/tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml
similarity index 75%
rename from libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more_ripple.xml
rename to tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml
index 16dea48..bd8942d 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more_ripple.xml
+++ b/tests/SilkFX/res/drawable/blur_activity_background_drawable_white.xml
@@ -14,7 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-        android:color="@android:color/system_neutral2_200">
-    <item android:drawable="@drawable/letterbox_education_ic_expand_more"/>
-</ripple>
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners android:radius="10dp"/>
+</shape>
diff --git a/tests/SilkFX/res/layout/activity_background_blur.xml b/tests/SilkFX/res/layout/activity_background_blur.xml
new file mode 100644
index 0000000..f13c088
--- /dev/null
+++ b/tests/SilkFX/res/layout/activity_background_blur.xml
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/background"
+    android:layout_width="390dp"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:padding="15dp"
+    android:orientation="vertical"
+    tools:context=".materials.BackgroundBlurActivity">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_horizontal"
+        android:padding="10dp"
+        android:textColor="#ffffffff"
+        android:text="Hello blurry world!"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:textColor="#ffffffff"
+            android:text="Background blur"/>
+
+        <SeekBar
+            android:id="@+id/set_background_blur"
+            android:min="0"
+            android:max="300"
+            android:layout_width="160dp"
+            android:layout_height="wrap_content"/>
+        <TextView
+            android:id="@+id/background_blur_radius"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#ffffffff"
+            android:ems="3"
+            android:gravity="center"
+            android:paddingLeft="10dp"
+            android:paddingRight="10dp"
+            android:text="TODO"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:textColor="#ffffffff"
+            android:text="Background alpha"/>
+
+        <SeekBar
+            android:id="@+id/set_background_alpha"
+            android:min="0"
+            android:max="100"
+            android:layout_width="160dp"
+            android:layout_height="wrap_content" />
+        <TextView
+            android:id="@+id/background_alpha"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="#ffffffff"
+            android:ems="3"
+            android:gravity="center"
+            android:paddingLeft="10dp"
+            android:paddingRight="10dp"
+            android:text="TODO"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:textColor="#ffffffff"
+            android:text="Blur behind"/>
+
+        <SeekBar
+            android:id="@+id/set_blur_behind"
+            android:min="0"
+            android:max="300"
+            android:layout_width="160dp"
+            android:layout_height="wrap_content" />
+        <TextView
+            android:id="@+id/blur_behind_radius"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:textColor="#ffffffff"
+            android:paddingLeft="10dp"
+            android:paddingRight="10dp"
+            android:ems="3"
+            android:text="TODO"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:textColor="#ffffffff"
+            android:text="Dim amount"/>
+
+        <SeekBar
+            android:id="@+id/set_dim_amount"
+            android:min="0"
+            android:max="100"
+            android:layout_width="160dp"
+            android:layout_height="wrap_content" />
+        <TextView
+            android:id="@+id/dim_amount"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:textColor="#ffffffff"
+            android:paddingLeft="10dp"
+            android:paddingRight="10dp"
+            android:ems="3"
+            android:text="TODO"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginTop="5dp"
+        android:orientation="vertical"
+        android:gravity="center">
+
+        <Button
+            android:id="@+id/toggle_blur_enabled"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Disable blur"
+            android:onClick="toggleForceBlurDisabled"/>
+
+        <Button
+            android:id="@+id/toggle_battery_saving_mode"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="TODO"
+            android:onClick="toggleBatterySavingMode"/>
+    </LinearLayout>
+    <requestFocus/>
+
+</LinearLayout>
diff --git a/tests/SilkFX/res/values/style.xml b/tests/SilkFX/res/values/style.xml
new file mode 100644
index 0000000..66edbb5
--- /dev/null
+++ b/tests/SilkFX/res/values/style.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+<!-- Styles for immersive actions UI. -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="Theme.BackgroundBlurTheme" parent= "Theme.AppCompat.Dialog">
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBlurBehindEnabled">true</item>
+        <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:windowElevation">0dp</item>
+        <item name="buttonStyle">@style/AppTheme.Button</item>
+        <item name="colorAccent">#bbffffff</item>
+    </style>
+    <style name="AppTheme.Button" parent="Widget.AppCompat.Button">
+        <item name="android:textColor">#ffffffff</item>
+    </style>
+
+</resources>
diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
index 9ed8d2f..7132ae8 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/Main.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -30,6 +30,7 @@
 import com.android.test.silkfx.app.EXTRA_TITLE
 import com.android.test.silkfx.hdr.GlowActivity
 import com.android.test.silkfx.materials.GlassActivity
+import com.android.test.silkfx.materials.BackgroundBlurActivity
 import kotlin.reflect.KClass
 
 class Demo(val name: String, val makeIntent: (Context) -> Intent) {
@@ -51,7 +52,8 @@
                 Demo("Blingy Notifications", R.layout.bling_notifications)
         )),
         DemoGroup("Materials", listOf(
-                Demo("Glass", GlassActivity::class)
+                Demo("Glass", GlassActivity::class),
+                Demo("Background Blur", BackgroundBlurActivity::class)
         ))
 )
 
@@ -126,4 +128,4 @@
 
         AllDemos.forEachIndexed { index, _ -> list.expandGroup(index) }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt
new file mode 100644
index 0000000..9d17d38
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/BackgroundBlurActivity.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2022 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.test.silkfx.materials
+
+import android.app.Activity
+import android.content.Intent
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.PaintDrawable
+import android.graphics.drawable.Drawable
+import android.os.Bundle
+import android.provider.Settings
+import android.util.TypedValue
+import android.view.View
+import android.view.WindowManager
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.Switch
+import android.widget.TextView
+import com.android.test.silkfx.R
+import com.android.internal.graphics.drawable.BackgroundBlurDrawable
+import android.widget.LinearLayout
+import android.widget.Button
+
+import android.view.ViewRootImpl
+
+class BackgroundBlurActivity : Activity(), SeekBar.OnSeekBarChangeListener  {
+    var mBackgroundDrawable = PaintDrawable(Color.WHITE)
+    var mBackgroundBlurRadius = 50
+    var mAlphaWithBlur = 0.2f
+    var mAlphaNoBlur = 0.5f
+
+    var mBlurBehindRadius = 10
+    var mDimAmountWithBlur = 0.2f
+    var mDimAmountNoBlur = 0.2f
+
+    var mBlurForceDisabled = false
+    var mBatterySavingModeOn = false
+
+    lateinit var blurBackgroundSeekBar: SeekBar
+    lateinit var backgroundAlphaSeekBar : SeekBar
+    lateinit var blurBehindSeekBar : SeekBar
+    lateinit var dimAmountSeekBar : SeekBar
+
+    val blurEnabledListener = { enabled : Boolean ->
+        blurBackgroundSeekBar.setProgress(mBackgroundBlurRadius)
+        blurBehindSeekBar.setProgress(mBlurBehindRadius)
+
+        if (enabled) {
+            setBackgroundBlur(mBackgroundBlurRadius)
+            setBackgroundColorAlpha(mAlphaWithBlur)
+
+            setBlurBehind(mBlurBehindRadius)
+            setDimAmount(mDimAmountWithBlur)
+
+            backgroundAlphaSeekBar.setProgress((mAlphaWithBlur * 100).toInt())
+            dimAmountSeekBar.setProgress((mDimAmountWithBlur * 100).toInt())
+        } else {
+            setBackgroundColorAlpha(mAlphaNoBlur)
+            setDimAmount(mDimAmountNoBlur)
+
+            backgroundAlphaSeekBar.setProgress((mAlphaNoBlur * 100).toInt())
+            dimAmountSeekBar.setProgress((mDimAmountNoBlur * 100).toInt())
+        }
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_background_blur)
+
+        window.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND)
+        window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+
+        mBackgroundDrawable.setCornerRadius(30f)
+        window.setBackgroundDrawable(mBackgroundDrawable)
+
+        mBatterySavingModeOn =
+            Settings.Global.getInt(getContentResolver(), Settings.Global.LOW_POWER_MODE, 0) == 1
+        setBatterySavingModeOn(mBatterySavingModeOn)
+
+        blurBackgroundSeekBar = requireViewById(R.id.set_background_blur)
+        backgroundAlphaSeekBar = requireViewById(R.id.set_background_alpha)
+        blurBehindSeekBar = requireViewById(R.id.set_blur_behind)
+        dimAmountSeekBar = requireViewById(R.id.set_dim_amount)
+
+        arrayOf(blurBackgroundSeekBar, backgroundAlphaSeekBar, blurBehindSeekBar, dimAmountSeekBar)
+                .forEach {
+                    it.setOnSeekBarChangeListener(this)
+                }
+    }
+
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        getWindowManager().addCrossWindowBlurEnabledListener(blurEnabledListener)
+    }
+
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        getWindowManager().removeCrossWindowBlurEnabledListener(blurEnabledListener)
+    }
+
+    override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+        when (seekBar) {
+            blurBackgroundSeekBar -> setBackgroundBlur(progress)
+            backgroundAlphaSeekBar -> setBackgroundColorAlpha(progress / 100.0f)
+            blurBehindSeekBar -> setBlurBehind(progress)
+            dimAmountSeekBar -> setDimAmount(progress / 100.0f)
+            else -> throw IllegalArgumentException("Unknown seek bar")
+        }
+    }
+
+    override fun onStartTrackingTouch(seekBar: SeekBar?) {}
+    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+
+    fun setBlurDisabled(disabled: Boolean) {
+        mBlurForceDisabled = disabled
+        Settings.Global.putInt(getContentResolver(), Settings.Global.DISABLE_WINDOW_BLURS,
+                if (mBlurForceDisabled) 1 else 0)
+        (findViewById(R.id.toggle_blur_enabled) as Button)
+                .setText(if (mBlurForceDisabled) "Enable blurs" else "Disable blurs")
+    }
+
+    fun toggleForceBlurDisabled(v: View) {
+        setBlurDisabled(!mBlurForceDisabled)
+    }
+
+    fun setBackgroundBlur(radius: Int) {
+        mBackgroundBlurRadius = radius
+        (findViewById(R.id.background_blur_radius) as TextView).setText(radius.toString())
+        window.setBackgroundBlurRadius(mBackgroundBlurRadius)
+    }
+
+    fun setBlurBehind(radius: Int) {
+        mBlurBehindRadius = radius
+        (findViewById(R.id.blur_behind_radius) as TextView).setText(radius.toString())
+        window.getAttributes().setBlurBehindRadius(mBlurBehindRadius)
+        window.setAttributes(window.getAttributes())
+    }
+
+    fun setDimAmount(amount: Float) {
+        if (getWindowManager().isCrossWindowBlurEnabled()) {
+            mDimAmountWithBlur = amount
+        } else {
+            mDimAmountNoBlur = amount
+        }
+        (findViewById(R.id.dim_amount) as TextView).setText("%.2f".format(amount))
+        window.getAttributes().dimAmount = amount
+        window.setAttributes(window.getAttributes())
+    }
+
+    fun setBatterySavingModeOn(on: Boolean) {
+        mBatterySavingModeOn = on
+        Settings.Global.putInt(getContentResolver(),
+            Settings.Global.LOW_POWER_MODE, if (on) 1 else 0)
+        (findViewById(R.id.toggle_battery_saving_mode) as Button).setText(
+            if (on) "Exit low power mode" else "Enter low power mode")
+    }
+
+    fun toggleBatterySavingMode(v: View) {
+        setBatterySavingModeOn(!mBatterySavingModeOn)
+    }
+
+    fun setBackgroundColorAlpha(alpha: Float) {
+        if (getWindowManager().isCrossWindowBlurEnabled()) {
+            mAlphaWithBlur = alpha
+        } else {
+            mAlphaNoBlur = alpha
+        }
+        (findViewById(R.id.background_alpha) as TextView).setText("%.2f".format(alpha))
+        mBackgroundDrawable.setAlpha((alpha * 255f).toInt())
+        getWindowManager().updateViewLayout(window.getDecorView(), window.getAttributes())
+    }
+}
diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp
deleted file mode 100644
index f87ca2e..0000000
--- a/tests/benchmarks/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (C) 2015 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.
-
-// build framework base core benchmarks
-// ============================================================
-
-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"],
-}
-
-java_library {
-    name: "networkStatsFactory-benchmarks",
-    installable: true,
-
-    srcs: ["src/**/*.java"],
-
-    libs: [
-        "caliper-api-target",
-        "services.core",
-    ],
-
-}
diff --git a/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java b/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java
deleted file mode 100644
index ef014f0..0000000
--- a/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import android.net.NetworkStats;
-import android.os.SystemClock;
-import com.android.server.net.NetworkStatsFactory;
-import com.google.caliper.AfterExperiment;
-import com.google.caliper.BeforeExperiment;
-import java.io.File;
-
-public class NetworkStatsFactoryBenchmark {
-    private File mStats;
-
-    // TODO: consider staging stats file with different number of rows
-
-    @BeforeExperiment
-    protected void setUp() {
-        mStats = new File("/proc/net/xt_qtaguid/stats");
-    }
-
-    @AfterExperiment
-    protected void tearDown() {
-        mStats = null;
-    }
-
-    public void timeReadNetworkStatsDetailJava(int reps) throws Exception {
-        for (int i = 0; i < reps; i++) {
-            NetworkStatsFactory.javaReadNetworkStatsDetail(mStats, NetworkStats.UID_ALL,
-                    // Looks like this was broken by change d0c5b9abed60b7bc056d026bf0f2b2235410fb70
-                    // Fixed compilation problem but needs addressing properly.
-                    new String[0], 999);
-        }
-    }
-
-    public void timeReadNetworkStatsDetailNative(int reps) {
-        for (int i = 0; i < reps; i++) {
-            final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
-            NetworkStatsFactory.nativeReadNetworkStatsDetail(
-                    stats, mStats.getAbsolutePath(), NetworkStats.UID_ALL,
-                    // Looks like this was broken by change d0c5b9abed60b7bc056d026bf0f2b2235410fb70
-                    // Fixed compilation problem but needs addressing properly.
-                    new String[0], 999, false);
-        }
-    }
-}
diff --git a/tests/benchmarks/src/com/android/server/net/OWNERS b/tests/benchmarks/src/com/android/server/net/OWNERS
deleted file mode 100644
index aa87958..0000000
--- a/tests/benchmarks/src/com/android/server/net/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /services/core/java/com/android/server/net/OWNERS
diff --git a/tests/componentalias/AndroidTest-template.xml b/tests/componentalias/AndroidTest-template.xml
index 2d46217..afdfe79 100644
--- a/tests/componentalias/AndroidTest-template.xml
+++ b/tests/componentalias/AndroidTest-template.xml
@@ -21,8 +21,6 @@
         <option name="test-file-name" value="ComponentAliasTests2.apk" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="run-command" value="am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android" />
-
         <!-- Exempt the helper APKs from the BG restriction, so they can start BG services. -->
         <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests" />
         <option name="run-command" value="cmd deviceidle whitelist +android.content.componentalias.tests.sub1" />
diff --git a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
index 89db2f7..9658d6f 100644
--- a/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
+++ b/tests/componentalias/src/android/content/componentalias/tests/BaseComponentAliasTest.java
@@ -17,6 +17,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.os.Build;
 import android.provider.DeviceConfig;
 import android.util.Log;
 
@@ -27,6 +28,7 @@
 import com.android.compatibility.common.util.TestUtils;
 
 import org.junit.AfterClass;
+import org.junit.Assume;
 import org.junit.Before;
 
 import java.util.function.Consumer;
@@ -37,7 +39,11 @@
     protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
             DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
     @Before
-    public void enableComponentAlias() throws Exception {
+    public void enableComponentAliasWithCompatFlag() throws Exception {
+        Assume.assumeTrue(Build.isDebuggable());
+        ShellUtils.runShellCommand(
+                "am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android");
+        sDeviceConfig.set("enable_experimental_component_alias", "");
         sDeviceConfig.set("component_alias_overrides", "");
 
         // Make sure the feature is actually enabled.
@@ -49,6 +55,8 @@
 
     @AfterClass
     public static void restoreDeviceConfig() throws Exception {
+        ShellUtils.runShellCommand(
+                "am compat disable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android");
         sDeviceConfig.close();
     }
 
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
new file mode 100644
index 0000000..52c6d5b
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasEnableWithDeviceConfigTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.componentalias.tests;
+
+import android.os.Build;
+import android.provider.DeviceConfig;
+
+import com.android.compatibility.common.util.DeviceConfigStateHelper;
+import com.android.compatibility.common.util.ShellUtils;
+import com.android.compatibility.common.util.TestUtils;
+
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class ComponentAliasEnableWithDeviceConfigTest {
+    protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
+            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+
+    @AfterClass
+    public static void restoreDeviceConfig() throws Exception {
+        sDeviceConfig.close();
+    }
+
+    @Test
+    public void enableComponentAliasWithCompatFlag() throws Exception {
+        Assume.assumeTrue(Build.isDebuggable());
+
+        sDeviceConfig.set("component_alias_overrides", "");
+
+        // First, disable with both compat-id and device config.
+        ShellUtils.runShellCommand(
+                "am compat disable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android");
+        sDeviceConfig.set("enable_experimental_component_alias", "");
+
+        TestUtils.waitUntil("Wait until component alias is actually enabled", () -> {
+            return ShellUtils.runShellCommand("dumpsys activity component-alias")
+                    .indexOf("Enabled: false") > 0;
+        });
+
+        // Then, enable by device config.
+        sDeviceConfig.set("enable_experimental_component_alias", "true");
+
+        // Make sure the feature is actually enabled.
+        TestUtils.waitUntil("Wait until component alias is actually enabled", () -> {
+            return ShellUtils.runShellCommand("dumpsys activity component-alias")
+                    .indexOf("Enabled: true") > 0;
+        });
+    }
+}
diff --git a/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
new file mode 100644
index 0000000..7935476
--- /dev/null
+++ b/tests/componentalias/src/android/content/componentalias/tests/ComponentAliasNotSupportedOnUserBuildTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.componentalias.tests;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Build;
+import android.provider.DeviceConfig;
+
+import com.android.compatibility.common.util.DeviceConfigStateHelper;
+import com.android.compatibility.common.util.ShellUtils;
+
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.Test;
+
+/**
+ * Test to make sure component-alias can't be enabled on user builds.
+ */
+public class ComponentAliasNotSupportedOnUserBuildTest {
+    protected static final DeviceConfigStateHelper sDeviceConfig = new DeviceConfigStateHelper(
+            DeviceConfig.NAMESPACE_ACTIVITY_MANAGER);
+
+    @AfterClass
+    public static void restoreDeviceConfig() throws Exception {
+        sDeviceConfig.close();
+    }
+
+    @Test
+    public void enableComponentAliasWithCompatFlag() throws Exception {
+        Assume.assumeFalse(Build.isDebuggable());
+
+        // Try to enable it by both the device config and compat-id.
+        sDeviceConfig.set("enable_experimental_component_alias", "true");
+        ShellUtils.runShellCommand(
+                "am compat enable --no-kill USE_EXPERIMENTAL_COMPONENT_ALIAS android");
+
+        // Sleep for an arbitrary amount of time, so the config would sink in, if there was
+        // no "not on user builds" check.
+
+        Thread.sleep(5000);
+
+        // Make sure the feature is still disabled.
+        assertThat(ShellUtils.runShellCommand("dumpsys activity component-alias")
+                .indexOf("Enabled: false") > 0).isTrue();
+    }
+}
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index 99f77fe..2c2c918 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -635,23 +635,11 @@
         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
         all_sequences.add(sequence)
         sequence_pieces.update(sequence)
-        if _emoji_sequences.get(sequence, None) == 'Emoji_Tag_Sequence':
-            # Add reverse of all emoji ZWJ sequences, which are added to the
-            # fonts as a workaround to get the sequences work in RTL text.
-            # TODO: test if these are actually needed by Minikin/HarfBuzz.
-            reversed_seq = reverse_emoji(sequence)
-            all_sequences.add(reversed_seq)
-            equivalent_emoji[reversed_seq] = sequence
 
     for sequence in adjusted_emoji_zwj_sequences.keys():
         sequence = tuple(ch for ch in sequence if ch != EMOJI_VS)
         all_sequences.add(sequence)
         sequence_pieces.update(sequence)
-        # Add reverse of all emoji ZWJ sequences, which are added to the fonts
-        # as a workaround to get the sequences work in RTL text.
-        reversed_seq = reverse_emoji(sequence)
-        all_sequences.add(reversed_seq)
-        equivalent_emoji[reversed_seq] = sequence
 
     for first, second in SAME_FLAG_MAPPINGS:
         equivalent_emoji[first] = second