Merge "Add new ColorScheme styles"
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index 9153426..50e0a1b 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -35446,51 +35446,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
@@ -35914,174 +35869,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;
diff --git a/core/api/current.txt b/core/api/current.txt
index 4777e3c..7d45ad8 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4069,7 +4069,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);
@@ -4970,7 +4970,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();
@@ -7611,7 +7611,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";
@@ -26391,75 +26391,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;
@@ -48972,7 +48903,7 @@
   }
 
   public interface OnBackInvokedDispatcherOwner {
-    method @Nullable public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
+    method @NonNull public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
   }
 
   public interface OnReceiveContentListener {
@@ -49400,7 +49331,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);
@@ -49604,7 +49535,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();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 4448a03..9737cde 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -139,9 +139,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,14 +283,6 @@
     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);
   }
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 311b110..07639fb 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -513,7 +513,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 1cba58c..6a458fb 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2826,8 +2826,8 @@
     field public static final String APP_PREDICTION_SERVICE = "app_prediction";
     field public static final String BACKUP_SERVICE = "backup";
     field public static final String BATTERY_STATS_SERVICE = "batterystats";
-    field @Deprecated public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
-    field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
+    field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
+    field @Deprecated public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
     field public static final String CLOUDSEARCH_SERVICE = "cloudsearch";
     field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
@@ -7952,7 +7952,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();
@@ -8336,23 +8336,6 @@
     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 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 MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
     ctor public MatchAllNetworkSpecifier();
     method public int describeContents();
@@ -14734,6 +14717,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsClientConfiguration> CREATOR;
     field public static final String RCS_PROFILE_1_0 = "UP_1.0";
     field public static final String RCS_PROFILE_2_3 = "UP_2.3";
+    field public static final String RCS_PROFILE_2_4 = "UP_2.4";
   }
 
   public final class RcsContactPresenceTuple implements android.os.Parcelable {
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..9d6fc0e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1607,10 +1607,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);
@@ -2820,7 +2816,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/app/Activity.java b/core/java/android/app/Activity.java
index 530666b..90c56ae 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6139,6 +6139,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
@@ -8742,17 +8746,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/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index cce7dd3..a58ceaa 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -215,6 +215,14 @@
     public abstract boolean isSystemReady();
 
     /**
+     * Returns package name given pid.
+     *
+     * @param pid The pid we are searching package name for.
+     */
+    @Nullable
+    public abstract String getPackageNameByPid(int pid);
+
+    /**
      * Sets if the given pid has an overlay UI or not.
      *
      * @param pid The pid we are setting overlay UI for.
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index a7fb83b..4b42ddc3 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -1449,15 +1449,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/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 79180cb..4187ba0 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -139,12 +139,10 @@
 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 +439,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
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 82cdf6f..6cd991b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1330,7 +1330,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";
 
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/content/Context.java b/core/java/android/content/Context.java
index 66903e0..6ffea3f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -408,6 +408,7 @@
      * @hide
      */
     @SystemApi
+    @Deprecated
     public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 0x00040000;
 
     /**
@@ -421,12 +422,13 @@
     public static final int BIND_SCHEDULE_LIKE_TOP_APP = 0x00080000;
 
     /**
-     * This flag has never been used.
+     * Flag for {@link #bindService}: allow background activity starts from the bound service's
+     * process.
+     * This flag is only respected if the caller is holding
+     * {@link android.Manifest.permission#START_ACTIVITIES_FROM_BACKGROUND}.
      * @hide
-     * @deprecated This flag has never been used.
      */
     @SystemApi
-    @Deprecated
     public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 0x00100000;
 
     /**
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..07227c5 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;
 
     /**
diff --git a/core/java/android/os/logcat/ILogcatManagerService.aidl b/core/java/android/os/logcat/ILogcatManagerService.aidl
index 68b5679..02db274 100644
--- a/core/java/android/os/logcat/ILogcatManagerService.aidl
+++ b/core/java/android/os/logcat/ILogcatManagerService.aidl
@@ -22,5 +22,7 @@
 interface ILogcatManagerService {
     void startThread(in int uid, in int gid, in int pid, in int fd);
     void finishThread(in int uid, in int gid, in int pid, in int fd);
+    void approve(in int uid, in int gid, in int pid, in int fd);
+    void decline(in int uid, in int gid, in int pid, in int fd);
 }
 
diff --git a/core/java/android/view/OnBackInvokedDispatcher.java b/core/java/android/view/OnBackInvokedDispatcher.java
index 05c312b..f3ca531 100644
--- a/core/java/android/view/OnBackInvokedDispatcher.java
+++ b/core/java/android/view/OnBackInvokedDispatcher.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
+import android.os.Build;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -32,6 +33,13 @@
  * target (a.k.a. the callback to be invoked next), or its behavior.
  */
 public abstract class OnBackInvokedDispatcher {
+
+    /** @hide */
+    public static final String TAG = "OnBackInvokedDispatcher";
+
+    /** @hide */
+    public static final boolean DEBUG = Build.isDebuggable();
+
     /** @hide */
     @IntDef({
             PRIORITY_DEFAULT,
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/View.java b/core/java/android/view/View.java
index 4ff7e229..36a97e4c 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;
 
@@ -31447,23 +31447,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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 386b277..3d86535 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,9 +313,9 @@
     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();
 
     /**
@@ -893,7 +893,6 @@
         mFastScrollSoundEffectsEnabled = audioManager.areNavigationRepeatSoundEffectsEnabled();
 
         mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
-        mFallbackOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow);
     }
 
     public static void addFirstDrawHandler(Runnable callback) {
@@ -1144,9 +1143,6 @@
                     if (pendingInsetsController != null) {
                         pendingInsetsController.replayAndAttach(mInsetsController);
                     }
-                    ((RootViewSurfaceTaker) mView)
-                            .provideWindowOnBackInvokedDispatcher()
-                            .attachToWindow(mWindowSession, mWindow);
                 }
 
                 try {
@@ -1193,6 +1189,7 @@
                         getAttachedWindowFrame(), 1f /* compactScale */,
                         mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
                 setFrame(mTmpFrames.frame);
+                registerBackCallbackOnWindow();
                 if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
                 if (res < WindowManagerGlobal.ADD_OKAY) {
                     mAttachInfo.mRootView = null;
@@ -8417,6 +8414,7 @@
 
             mAdded = false;
         }
+        mOnBackInvokedDispatcher.detachFromWindow();
         WindowManagerGlobal.getInstance().doRemoveView(this);
     }
 
@@ -10771,12 +10769,17 @@
      * 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();
-        }
-        return mFallbackOnBackInvokedDispatcher;
+    @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);
     }
 
     @Override
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..509bbd4
--- /dev/null
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -0,0 +1,162 @@
+/*
+ * 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 extends 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));
+        }
+        synchronized (mLock) {
+            mCallbacks.add(Pair.create(callback, priority));
+            if (mActualDispatcherOwner != null) {
+                mActualDispatcherOwner.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+                        callback, priority);
+            }
+
+        }
+    }
+
+    @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));
+        }
+    }
+
+    /**
+     * 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) {
+            dispatcher.registerOnBackInvokedCallback(callbackPair.first,
+                    callbackPair.second);
+        }
+        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/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/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/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 85504ce..9db715b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6540,6 +6540,14 @@
                   android:exported="false">
         </activity>
 
+        <activity android:name="com.android.server.logcat.LogAccessConfirmationActivity"
+                  android:theme="@style/Theme.Dialog.Confirmation"
+                  android:excludeFromRecents="true"
+                  android:process=":ui"
+                  android:label="@string/log_access_confirmation_title"
+                  android:exported="false">
+        </activity>
+
         <activity android:name="com.android.server.notification.NASLearnMoreActivity"
                   android:theme="@style/Theme.Dialog.Confirmation"
                   android:excludeFromRecents="true"
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/strings.xml b/core/res/res/values/strings.xml
index 52c6205..0dbd417 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5689,6 +5689,20 @@
     <!-- Title for the harmful app warning dialog. [CHAR LIMIT=40] -->
     <string name="harmful_app_warning_title">Harmful app detected</string>
 
+    <!-- Title for the log access confirmation dialog. [CHAR LIMIT=40] -->
+    <string name="log_access_confirmation_title">System log access request</string>
+    <!-- Label for the allow button on the log access confirmation dialog. [CHAR LIMIT=20] -->
+    <string name="log_access_confirmation_allow">Only this time</string>
+    <!-- Label for the deny button on the log access confirmation dialog. [CHAR LIMIT=20] -->
+    <string name="log_access_confirmation_deny">Don\u2019t allow</string>
+
+    <!-- Content for the log access confirmation dialog. [CHAR LIMIT=NONE]-->
+    <string name="log_access_confirmation_body"><xliff:g id="log_access_app_name" example="Example App">%s</xliff:g> requests system logs for functional debugging.
+        These logs might contain information that apps and services on your device have written.</string>
+
+    <!-- Privacy notice do not show [CHAR LIMIT=20] -->
+    <string name="log_access_do_not_show_again">Don\u2019t show again</string>
+
     <!-- Text describing a permission request for one app to show another app's
          slices [CHAR LIMIT=NONE] -->
     <string name="slices_permission_request"><xliff:g id="app" example="Example App">%1$s</xliff:g> wants to show <xliff:g id="app_2" example="Other Example App">%2$s</xliff:g> slices</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index facfdb2..764b273 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3865,6 +3865,11 @@
   <java-symbol type="string" name="harmful_app_warning_title" />
   <java-symbol type="layout" name="harmful_app_warning_dialog" />
 
+  <java-symbol type="string" name="log_access_confirmation_allow" />
+  <java-symbol type="string" name="log_access_confirmation_deny" />
+  <java-symbol type="string" name="log_access_confirmation_title" />
+  <java-symbol type="string" name="log_access_confirmation_body" />
+
   <java-symbol type="string" name="config_defaultAssistantAccessComponent" />
 
   <java-symbol type="string" name="slices_permission_request" />
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
index bd987a0..6639c02 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
@@ -20,6 +20,7 @@
 
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.BATTERY_STATS"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
 
     <application
         android:theme="@style/Theme"
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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index d002601..a331b6e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -474,6 +474,7 @@
         <!-- Permission needed for CTS test - WifiManagerTest -->
         <permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
         <permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
+        <permission name="android.permission.NEARBY_WIFI_DEVICES" />
         <permission name="android.permission.OVERRIDE_WIFI_CONFIG" />
         <!-- Permission required for CTS test CarrierMessagingServiceWrapperTest -->
         <permission name="android.permission.BIND_CARRIER_SERVICES"/>
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/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/drawable/letterbox_education_ic_expand_more_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more_ripple.xml
deleted file mode 100644
index 16dea48..0000000
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more_ripple.xml
+++ /dev/null
@@ -1,20 +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.
-  -->
-<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
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/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/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index 3cfa541..d022ec1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -89,9 +89,17 @@
     /**
      * Version of startTasks using legacy transition system.
      */
-     oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
-                            int sideTaskId, in Bundle sideOptions, int sidePosition,
-                            float splitRatio, in RemoteAnimationAdapter adapter) = 11;
+    oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
+            int sideTaskId, in Bundle sideOptions, int sidePosition,
+            float splitRatio, in RemoteAnimationAdapter adapter) = 11;
+
+    /**
+     * Start a pair of intent and task using legacy transition system.
+     */
+    oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent,
+            in Intent fillInIntent, int taskId, boolean intentFirst, in Bundle mainOptions,
+            in Bundle sideOptions, int sidePosition, float splitRatio,
+            in RemoteAnimationAdapter adapter) = 12;
 
     /**
      * Blocking call that notifies and gets additional split-screen targets when entering
@@ -100,5 +108,7 @@
      * @param appTargets apps that will be re-parented to display area
      */
     RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
-                                                   in RemoteAnimationTarget[] appTargets) = 12;
+                                                   in RemoteAnimationTarget[] appTargets) = 13;
+
+
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 3e6dc82..990b53a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -641,6 +641,18 @@
         }
 
         @Override
+        public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
+                Intent fillInIntent, int taskId, boolean intentFirst, Bundle mainOptions,
+                Bundle sideOptions, int sidePosition, float splitRatio,
+                RemoteAnimationAdapter adapter) {
+            executeRemoteCallWithTaskPermission(mController,
+                    "startIntentAndTaskWithLegacyTransition", (controller) ->
+                            controller.mStageCoordinator.startIntentAndTaskWithLegacyTransition(
+                                    pendingIntent, fillInIntent, taskId, intentFirst, mainOptions,
+                                    sideOptions, sidePosition, splitRatio, adapter));
+        }
+
+        @Override
         public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
                 int sideTaskId, @Nullable Bundle sideOptions,
                 @SplitPosition int sidePosition, float splitRatio,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a2c2f59..219530b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -57,8 +57,10 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
 import android.app.WindowConfiguration;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.devicestate.DeviceStateManager;
@@ -467,6 +469,116 @@
         mTaskOrganizer.applyTransaction(wct);
     }
 
+    /** Start an intent and a task ordered by {@code intentFirst}. */
+    void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent,
+            int taskId, boolean intentFirst, @Nullable Bundle mainOptions,
+            @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
+            RemoteAnimationAdapter adapter) {
+        // TODO: try pulling the first chunk of this method into a method so that it can be shared
+        // with startTasksWithLegacyTransition. So far attempts to do so result in failure in split.
+
+        // Init divider first to make divider leash for remote animation target.
+        mSplitLayout.init();
+        // Set false to avoid record new bounds with old task still on top;
+        mShouldUpdateRecents = false;
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+        prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
+        prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
+        // Need to add another wrapper here in shell so that we can inject the divider bar
+        // and also manage the process elevation via setRunningRemote
+        IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
+            @Override
+            public void onAnimationStart(@WindowManager.TransitionOldType int transit,
+                    RemoteAnimationTarget[] apps,
+                    RemoteAnimationTarget[] wallpapers,
+                    RemoteAnimationTarget[] nonApps,
+                    final IRemoteAnimationFinishedCallback finishedCallback) {
+                RemoteAnimationTarget[] augmentedNonApps =
+                        new RemoteAnimationTarget[nonApps.length + 1];
+                for (int i = 0; i < nonApps.length; ++i) {
+                    augmentedNonApps[i] = nonApps[i];
+                }
+                augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
+
+                IRemoteAnimationFinishedCallback wrapCallback =
+                        new IRemoteAnimationFinishedCallback.Stub() {
+                            @Override
+                            public void onAnimationFinished() throws RemoteException {
+                                mShouldUpdateRecents = true;
+                                mSyncQueue.queue(evictWct);
+                                mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
+                                finishedCallback.onAnimationFinished();
+                            }
+                        };
+                try {
+                    try {
+                        ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
+                                adapter.getCallingApplication());
+                    } catch (SecurityException e) {
+                        Slog.e(TAG, "Unable to boost animation thread. This should only happen"
+                                + " during unit tests");
+                    }
+                    adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
+                            augmentedNonApps, wrapCallback);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error starting remote animation", e);
+                }
+            }
+
+            @Override
+            public void onAnimationCancelled() {
+                mShouldUpdateRecents = true;
+                mSyncQueue.queue(evictWct);
+                mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
+                try {
+                    adapter.getRunner().onAnimationCancelled();
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error starting remote animation", e);
+                }
+            }
+        };
+        RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
+                wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
+
+        if (mainOptions == null) {
+            mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
+        } else {
+            ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
+            mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
+            mainOptions = mainActivityOptions.toBundle();
+        }
+
+        sideOptions = sideOptions != null ? sideOptions : new Bundle();
+        setSideStagePosition(sidePosition, wct);
+
+        mSplitLayout.setDivideRatio(splitRatio);
+        if (mMainStage.isActive()) {
+            mMainStage.moveToTop(getMainStageBounds(), wct);
+        } else {
+            // Build a request WCT that will launch both apps such that task 0 is on the main stage
+            // while task 1 is on the side stage.
+            mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
+        }
+        mSideStage.moveToTop(getSideStageBounds(), wct);
+
+        // Make sure the launch options will put tasks in the corresponding split roots
+        addActivityOptions(mainOptions, mMainStage);
+        addActivityOptions(sideOptions, mSideStage);
+
+        // Add task launch requests
+        if (intentFirst) {
+            wct.sendPendingIntent(pendingIntent, fillInIntent, mainOptions);
+            wct.startTask(taskId, sideOptions);
+        } else {
+            wct.startTask(taskId, mainOptions);
+            wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
+        }
+
+        // Using legacy transitions, so we can't use blast sync since it conflicts.
+        mTaskOrganizer.applyTransaction(wct);
+    }
+
     /**
      * Collects all the current child tasks of a specific split and prepares transaction to evict
      * them to display.
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/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..b738c47 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
@@ -75,7 +75,8 @@
                 screenshotSurface,
                 hardwareBuffer,
                 new WindowConfiguration(),
-                new RemoteCallback((bundle) -> {}));
+                new RemoteCallback((bundle) -> {}),
+                null);
         try {
             doReturn(navigationInfo).when(mActivityTaskManager).startBackNavigation();
         } catch (RemoteException ex) {
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/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp
index 54538d9..6329565 100644
--- a/packages/ConnectivityT/framework-t/Android.bp
+++ b/packages/ConnectivityT/framework-t/Android.bp
@@ -158,7 +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 +166,7 @@
 filegroup {
     name: "framework-connectivity-tiramisu-updatable-sources",
     srcs: [
+        ":framework-connectivity-ipsec-sources",
         ":framework-connectivity-nsd-sources",
         ":framework-connectivity-tiramisu-internal-sources",
     ],
diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
index 630f902e..577ac54 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
@@ -48,5 +48,14 @@
                     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);
+                }
+        );
     }
 }
diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp
index 24bc91d..d2d6ef0 100644
--- a/packages/ConnectivityT/service/Android.bp
+++ b/packages/ConnectivityT/service/Android.bp
@@ -83,7 +83,6 @@
     name: "services.connectivity-tiramisu-sources",
     srcs: [
         ":services.connectivity-ethernet-sources",
-        ":services.connectivity-ipsec-sources",
         ":services.connectivity-netstats-sources",
     ],
     path: "src",
@@ -93,6 +92,7 @@
 filegroup {
     name: "services.connectivity-tiramisu-updatable-sources",
     srcs: [
+        ":services.connectivity-ipsec-sources",
         ":services.connectivity-nsd-sources",
     ],
     path: "src",
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/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ca90fbe..6f4cd4a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -533,6 +533,7 @@
     <!-- Permission needed for CTS test - WifiManagerTest -->
     <uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
     <uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
+    <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
     <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
 
     <!-- Permission required for CTS tests to enable/disable rate limiting toasts. -->
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/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/dream_overlay_complication_clock_time.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
index a41d34f..82c8d5f 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
@@ -20,7 +20,7 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:paddingLeft="@dimen/dream_overlay_complication_clock_time_padding_left"
-    android:fontFamily="sans-serif-thin"
+    android:fontFamily="@font/clock"
     android:textColor="@android:color/white"
     android:format12Hour="h:mm"
     android:format24Hour="kk:mm"
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/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/dreams/complication/dagger/DreamClockTimeComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
index 053c5b3..d539f5c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
@@ -22,6 +22,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.TextClock;
 
 import com.android.internal.util.Preconditions;
 import com.android.systemui.R;
@@ -78,6 +79,8 @@
                 "clock_time_complication_layout_params";
         // Order weight of insert into parent container
         int INSERT_ORDER_WEIGHT = 0;
+        String TAG_WEIGHT = "'wght' ";
+        int WEIGHT = 200;
 
         /**
          * Provides the complication view.
@@ -86,10 +89,12 @@
         @DreamClockTimeComplicationScope
         @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
         static View provideComplicationView(LayoutInflater layoutInflater) {
-            return Preconditions.checkNotNull(
-                    layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
-                            null, false),
+            final TextClock view = Preconditions.checkNotNull((TextClock)
+                            layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
+                                    null, false),
                     "R.layout.dream_overlay_complication_clock_time did not properly inflated");
+            view.setFontVariationSettings(TAG_WEIGHT + WEIGHT);
+            return view;
         }
 
         /**
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/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index 8684509..663877c 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));
     }
 
     /** */
@@ -128,6 +130,7 @@
             MediaTttFlags mediaTttFlags,
             CommandRegistry commandRegistry,
             Context context,
+            @Main Executor mainExecutor,
             MediaTttChipControllerReceiver mediaTttChipControllerReceiver) {
         if (!mediaTttFlags.isMediaTttEnabled()) {
             return Optional.empty();
@@ -136,6 +139,7 @@
                 new MediaTttCommandLineHelper(
                         commandRegistry,
                         context,
+                        mainExecutor,
                         mediaTttChipControllerReceiver));
     }
 
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..1ea21ce 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -21,13 +21,15 @@
 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.dagger.qualifiers.Main
 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.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 +38,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,13 +49,36 @@
 class MediaTttCommandLineHelper @Inject constructor(
     commandRegistry: CommandRegistry,
     private val context: Context,
+    @Main private val mainExecutor: Executor,
     private val mediaTttChipControllerReceiver: MediaTttChipControllerReceiver,
 ) {
-   private val appIconDrawable =
+    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(
@@ -68,22 +94,59 @@
                     .addFeature("feature")
                     .build()
 
+            @StatusBarManager.MediaTransferSenderState
+            val displayState = stateStringToStateInt[args[1]]
+            if (displayState == null) {
+                pw.println("Invalid command name")
+                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>")
         }
     }
 
+    // TODO(b/216318437): Migrate the receiver callbacks to StatusBarManager.
+
     /** A command to DISPLAY the media ttt chip on the RECEIVER device. */
     inner class AddChipCommandReceiver : Command {
         override fun execute(pw: PrintWriter, args: List<String>) {
@@ -110,29 +173,15 @@
 @VisibleForTesting
 const val SENDER_COMMAND = "media-ttt-chip-sender"
 @VisibleForTesting
-const val REMOVE_CHIP_COMMAND_SENDER_TAG = "media-ttt-chip-remove-sender"
-@VisibleForTesting
 const val ADD_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-add-receiver"
 @VisibleForTesting
 const val REMOVE_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-remove-receiver"
 @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"
+val FAR_FROM_RECEIVER_STATE = "FarFromReceiver"
 
 private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon"
-private const val TAG = "MediaTapToTransferCli"
+private const val CLI_TAG = "MediaTransferCli"
+
+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/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/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
new file mode 100644
index 0000000..eb341563
--- /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, false)
+
+            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/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/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 48255b5..6d1bbee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -34,8 +34,6 @@
 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;
 
@@ -91,9 +89,4 @@
     /** */
     @Binds
     QSHost provideQsHost(QSTileHost controllerImpl);
-
-    /** */
-    @Binds
-    RunningFgsController provideRunningFgsController(
-            RunningFgsControllerImpl runningFgsController);
 }
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..b328ae8 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
@@ -226,8 +226,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()));
@@ -1098,7 +1103,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 +1121,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 +1145,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;
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/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/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/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
index 5f800eb..c3d8d24 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,35 @@
 
 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,15 +61,19 @@
     private lateinit var mediaTttCommandLineHelper: MediaTttCommandLineHelper
 
     @Mock
+    private lateinit var statusBarManager: StatusBarManager
+    @Mock
     private lateinit var mediaTttChipControllerReceiver: MediaTttChipControllerReceiver
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        context.addMockSystemService(Context.STATUS_BAR_SERVICE, statusBarManager)
         mediaTttCommandLineHelper =
             MediaTttCommandLineHelper(
                 commandRegistry,
                 context,
+                FakeExecutor(FakeSystemClock()),
                 mediaTttChipControllerReceiver,
             )
     }
@@ -88,91 +103,116 @@
         ) { EmptyCommand() }
     }
 
-    /* TODO(b/216318437): Revive these tests using the new SystemApis.
     @Test
-    fun sender_moveCloserToStartCast_serviceCallbackCalled() {
-        commandRegistry.onShellCommand(pw, getMoveCloserToStartCastCommand())
+    fun sender_almostCloseToStartCast_serviceCallbackCalled() {
+        commandRegistry.onShellCommand(
+            pw, getSenderCommand(AlmostCloseToStartCast::class.simpleName!!)
+        )
 
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
-
-        val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
-        verify(mediaSenderService).closeToReceiverToStartCast(any(), capture(deviceInfoCaptor))
-        assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+        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)
     }
 
     @Test
-    fun sender_moveCloserToEndCast_serviceCallbackCalled() {
-        commandRegistry.onShellCommand(pw, getMoveCloserToEndCastCommand())
+    fun sender_almostCloseToEndCast_serviceCallbackCalled() {
+        commandRegistry.onShellCommand(
+            pw, getSenderCommand(AlmostCloseToEndCast::class.simpleName!!)
+        )
 
-        assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
-
-        val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
-        verify(mediaSenderService).closeToReceiverToEndCast(any(), capture(deviceInfoCaptor))
-        assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+        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())
+        verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+            eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER),
+            any(),
+            nullable(),
+            nullable())
     }
 
-     */
-
     @Test
     fun receiver_addCommand_chipAdded() {
         commandRegistry.onShellCommand(pw, arrayOf(ADD_CHIP_COMMAND_RECEIVER_TAG))
@@ -187,61 +227,8 @@
         verify(mediaTttChipControllerReceiver).removeChip()
     }
 
-    private fun getMoveCloserToStartCastCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            MOVE_CLOSER_TO_START_CAST_COMMAND_NAME
-        )
-
-    private fun getMoveCloserToEndCastCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            MOVE_CLOSER_TO_END_CAST_COMMAND_NAME
-        )
-
-    private fun getTransferToReceiverTriggeredCommand(): Array<String> =
-        arrayOf(
-            SENDER_COMMAND,
-            DEVICE_NAME,
-            TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME
-        )
-
-    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 getSenderCommand(displayState: String): Array<String> =
+        arrayOf(SENDER_COMMAND, DEVICE_NAME, displayState)
 
     class EmptyCommand : Command {
         override fun execute(pw: PrintWriter, args: List<String>) {
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/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/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 8fb066b..cb248b0 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;
@@ -872,6 +874,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 +1003,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") {};
 
@@ -969,6 +1039,10 @@
         verify(mOnRenderListListener).onRenderList(anyList());
 
         clearInvocations(mOnRenderListListener);
+        sectionComparator.invalidateList();
+        verify(mOnRenderListListener).onRenderList(anyList());
+
+        clearInvocations(mOnRenderListListener);
         preRenderInvalidator.invalidateList();
         verify(mOnRenderListListener).onRenderList(anyList());
     }
@@ -2037,16 +2111,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 +2245,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/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/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/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 6a7afd9..2d328d8 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -539,7 +539,13 @@
     @GuardedBy("mLock")
     private void notifyAllPolicyListenersLocked() {
         for (final PolicyListenerBinderDeath policyListener : mRegisteredPolicyListeners.values()) {
-            Binder.withCleanCallingIdentity(() -> policyListener.mListener.onPolicyChanged());
+            Binder.withCleanCallingIdentity(() -> {
+                try {
+                    policyListener.mListener.onPolicyChanged();
+                } catch (RemoteException e) {
+                    logDbg("VcnStatusCallback threw on VCN status change", e);
+                }
+            });
         }
     }
 
@@ -548,8 +554,13 @@
             @NonNull ParcelUuid subGroup, @VcnStatusCode int statusCode) {
         for (final VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
             if (isCallbackPermissioned(cbInfo, subGroup)) {
-                Binder.withCleanCallingIdentity(
-                        () -> cbInfo.mCallback.onVcnStatusChanged(statusCode));
+                Binder.withCleanCallingIdentity(() -> {
+                    try {
+                        cbInfo.mCallback.onVcnStatusChanged(statusCode);
+                    } catch (RemoteException e) {
+                        logDbg("VcnStatusCallback threw on VCN status change", e);
+                    }
+                });
             }
         }
     }
@@ -1222,13 +1233,17 @@
                 // Notify all registered StatusCallbacks for this subGroup
                 for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
                     if (isCallbackPermissioned(cbInfo, mSubGroup)) {
-                        Binder.withCleanCallingIdentity(
-                                () ->
-                                        cbInfo.mCallback.onGatewayConnectionError(
-                                                gatewayConnectionName,
-                                                errorCode,
-                                                exceptionClass,
-                                                exceptionMessage));
+                        Binder.withCleanCallingIdentity(() -> {
+                            try {
+                                cbInfo.mCallback.onGatewayConnectionError(
+                                        gatewayConnectionName,
+                                        errorCode,
+                                        exceptionClass,
+                                        exceptionMessage);
+                            } catch (RemoteException e) {
+                                logDbg("VcnStatusCallback threw on VCN status change", e);
+                            }
+                        });
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fafe908..cbb40aa 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;
@@ -16089,6 +16089,23 @@
         }
 
         /**
+         * Returns package name by pid.
+         */
+        @Override
+        @Nullable
+        public String getPackageNameByPid(int pid) {
+            synchronized (mPidsSelfLocked) {
+                final ProcessRecord app = mPidsSelfLocked.get(pid);
+
+                if (app != null && app.info != null) {
+                    return app.info.packageName;
+                }
+
+                return null;
+            }
+        }
+
+        /**
          * Sets if the given pid has an overlay UI or not.
          *
          * @param pid The pid we are setting overlay UI for.
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 960fbf1..145a298 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();
 
@@ -510,10 +511,11 @@
             }
             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 {
@@ -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/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/logcat/LogAccessConfirmationActivity.java b/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
new file mode 100644
index 0000000..6b442a6
--- /dev/null
+++ b/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
@@ -0,0 +1,130 @@
+/*
+ * 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.logcat;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.os.ServiceManager;
+import android.os.logcat.ILogcatManagerService;
+import android.util.Slog;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+
+/**
+ * This dialog is shown to the user before an activity in a harmful app is launched.
+ *
+ * See {@code PackageManager.setLogcatAppInfo} for more info.
+ */
+public class LogAccessConfirmationActivity extends AlertActivity implements
+        DialogInterface.OnClickListener {
+    private static final String TAG = LogAccessConfirmationActivity.class.getSimpleName();
+
+    private String mPackageName;
+    private IntentSender mTarget;
+    private final ILogcatManagerService mLogcatManagerService =
+            ILogcatManagerService.Stub.asInterface(ServiceManager.getService("logcat"));
+
+    private int mUid;
+    private int mGid;
+    private int mPid;
+    private int mFd;
+
+    private static final String EXTRA_UID = "uid";
+    private static final String EXTRA_GID = "gid";
+    private static final String EXTRA_PID = "pid";
+    private static final String EXTRA_FD = "fd";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Intent intent = getIntent();
+        mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+        mUid = intent.getIntExtra("uid", 0);
+        mGid = intent.getIntExtra("gid", 0);
+        mPid = intent.getIntExtra("pid", 0);
+        mFd = intent.getIntExtra("fd", 0);
+
+        final AlertController.AlertParams p = mAlertParams;
+        p.mTitle = getString(R.string.log_access_confirmation_title);
+        p.mView = createView();
+
+        p.mPositiveButtonText = getString(R.string.log_access_confirmation_allow);
+        p.mPositiveButtonListener = this;
+        p.mNegativeButtonText = getString(R.string.log_access_confirmation_deny);
+        p.mNegativeButtonListener = this;
+
+        mAlert.installContent(mAlertParams);
+    }
+
+    private View createView() {
+        final View view = getLayoutInflater().inflate(R.layout.harmful_app_warning_dialog,
+                null /*root*/);
+        ((TextView) view.findViewById(R.id.app_name_text))
+                .setText(mPackageName);
+        ((TextView) view.findViewById(R.id.message))
+                .setText(getIntent().getExtras().getString("body"));
+        return view;
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        switch (which) {
+            case DialogInterface.BUTTON_POSITIVE:
+                try {
+                    mLogcatManagerService.approve(mUid, mGid, mPid, mFd);
+                } catch (Throwable t) {
+                    Slog.e(TAG, "Could not start the LogcatManagerService.", t);
+                }
+                finish();
+                break;
+            case DialogInterface.BUTTON_NEGATIVE:
+                try {
+                    mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
+                } catch (Throwable t) {
+                    Slog.e(TAG, "Could not start the LogcatManagerService.", t);
+                }
+                finish();
+                break;
+        }
+    }
+
+    /**
+     * Create the Intent for a LogAccessConfirmationActivity.
+     */
+    public static Intent createIntent(Context context, String targetPackageName,
+            IntentSender target, int uid, int gid, int pid, int fd) {
+        final Intent intent = new Intent();
+        intent.setClass(context, LogAccessConfirmationActivity.class);
+        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
+        intent.putExtra(EXTRA_UID, uid);
+        intent.putExtra(EXTRA_GID, gid);
+        intent.putExtra(EXTRA_PID, pid);
+        intent.putExtra(EXTRA_FD, fd);
+
+        return intent;
+    }
+
+}
diff --git a/services/core/java/com/android/server/logcat/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index ff6372ae..140c6d4 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -16,20 +16,36 @@
 
 package com.android.server.logcat;
 
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityManagerInternal;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.ILogd;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.os.logcat.ILogcatManagerService;
 import android.util.Slog;
 
+import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
+import java.util.Arrays;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 /**
- * Service responsible for manage the access to Logcat.
+ * Service responsible for managing the access to Logcat.
  */
 public final class LogcatManagerService extends SystemService {
 
@@ -38,6 +54,43 @@
     private final BinderService mBinderService;
     private final ExecutorService mThreadExecutor;
     private ILogd mLogdService;
+    private NotificationManager mNotificationManager;
+    private @NonNull ActivityManager mActivityManager;
+    private ActivityManagerInternal mActivityManagerInternal;
+    private static final int MAX_UID_IMPORTANCE_COUNT_LISTENER = 2;
+    private static int sUidImportanceListenerCount = 0;
+    private static final int AID_SHELL_UID = 2000;
+
+    // TODO This allowlist is just a temporary workaround for the tests:
+    //      FrameworksServicesTests
+    //      PlatformRuleTests
+    // After adapting the test suites, the allowlist will be removed in
+    // the upcoming bug fix patches.
+    private static final String[] ALLOWABLE_TESTING_PACKAGES = {
+            "android.platform.test.rule.tests",
+            "com.android.frameworks.servicestests"
+    };
+
+    // TODO Same as the above ALLOWABLE_TESTING_PACKAGES.
+    private boolean isAllowableTestingPackage(int uid) {
+        PackageManager pm = mContext.getPackageManager();
+
+        String[] packageNames = pm.getPackagesForUid(uid);
+
+        if (ArrayUtils.isEmpty(packageNames)) {
+            return false;
+        }
+
+        for (String name : packageNames) {
+            Slog.e(TAG, "isAllowableTestingPackage: " + name);
+
+            if (Arrays.asList(ALLOWABLE_TESTING_PACKAGES).contains(name)) {
+                return true;
+            }
+        }
+
+        return false;
+    };
 
     private final class BinderService extends ILogcatManagerService.Stub {
         @Override
@@ -51,6 +104,197 @@
             // the logd data access is finished.
             mThreadExecutor.execute(new LogdMonitor(uid, gid, pid, fd, false));
         }
+
+        @Override
+        public void approve(int uid, int gid, int pid, int fd) {
+            try {
+                getLogdService().approve(uid, gid, pid, fd);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+
+        @Override
+        public void decline(int uid, int gid, int pid, int fd) {
+            try {
+                getLogdService().decline(uid, gid, pid, fd);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private ILogd getLogdService() {
+        synchronized (LogcatManagerService.this) {
+            if (mLogdService == null) {
+                LogcatManagerService.this.addLogdService();
+            }
+            return mLogdService;
+        }
+    }
+
+    private String getBodyString(Context context, String callingPackage, int uid) {
+        PackageManager pm = context.getPackageManager();
+        try {
+            return context.getString(
+                com.android.internal.R.string.log_access_confirmation_body,
+                pm.getApplicationInfoAsUser(callingPackage, PackageManager.MATCH_DIRECT_BOOT_AUTO,
+                    UserHandle.getUserId(uid)).loadLabel(pm));
+        } catch (NameNotFoundException e) {
+            // App name is unknown.
+            return null;
+        }
+    }
+
+    private void sendNotification(int notificationId, String clientInfo, int uid, int gid, int pid,
+            int fd) {
+
+        final ActivityManagerInternal activityManagerInternal =
+                LocalServices.getService(ActivityManagerInternal.class);
+
+        PackageManager pm = mContext.getPackageManager();
+        String packageName = activityManagerInternal.getPackageNameByPid(pid);
+        if (packageName != null) {
+            String notificationBody = getBodyString(mContext, packageName, uid);
+
+            final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
+                    packageName, null, uid, gid, pid, fd);
+
+            if (notificationBody == null) {
+                // Decline the logd access if the nofitication body is unknown
+                Slog.e(TAG, "Unknown notification body, declining the logd access");
+                declineLogdAccess(uid, gid, pid, fd);
+                return;
+            }
+
+            // TODO Next version will replace notification with dialogue
+            // per UX guidance.
+            generateNotificationWithBodyContent(notificationId, clientInfo, notificationBody,
+                    mIntent);
+            return;
+
+        }
+
+        String[] packageNames = pm.getPackagesForUid(uid);
+
+        if (ArrayUtils.isEmpty(packageNames)) {
+            // Decline the logd access if the app name is unknown
+            Slog.e(TAG, "Unknown calling package name, declining the logd access");
+            declineLogdAccess(uid, gid, pid, fd);
+            return;
+        }
+
+        String firstPackageName = packageNames[0];
+
+        if (firstPackageName == null || firstPackageName.length() == 0) {
+            // Decline the logd access if the package name from uid is unknown
+            Slog.e(TAG, "Unknown calling package name, declining the logd access");
+            declineLogdAccess(uid, gid, pid, fd);
+            return;
+        }
+
+        String notificationBody = getBodyString(mContext, firstPackageName, uid);
+
+        final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
+                firstPackageName, null, uid, gid, pid, fd);
+
+        if (notificationBody == null) {
+            Slog.e(TAG, "Unknown notification body, declining the logd access");
+            declineLogdAccess(uid, gid, pid, fd);
+            return;
+        }
+
+        // TODO Next version will replace notification with dialogue
+        // per UX guidance.
+        generateNotificationWithBodyContent(notificationId, clientInfo,
+                notificationBody, mIntent);
+    }
+
+    private void declineLogdAccess(int uid, int gid, int pid, int fd) {
+        try {
+            getLogdService().decline(uid, gid, pid, fd);
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Fails to call remote functions ", ex);
+        }
+    }
+
+    private void generateNotificationWithBodyContent(int notificationId, String clientInfo,
+            String notificationBody, Intent intent) {
+        final Notification.Builder notificationBuilder = new Notification.Builder(
+                mContext,
+                SystemNotificationChannels.ACCESSIBILITY_SECURITY_POLICY);
+        intent.setFlags(
+                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        intent.setIdentifier(String.valueOf(notificationId) + clientInfo);
+        intent.putExtra("body", notificationBody);
+
+        notificationBuilder
+            .setSmallIcon(R.drawable.ic_info)
+            .setContentTitle(
+                mContext.getString(R.string.log_access_confirmation_title))
+            .setContentText(notificationBody)
+            .setContentIntent(
+                PendingIntent.getActivity(mContext, 0, intent,
+                    PendingIntent.FLAG_IMMUTABLE))
+            .setTicker(mContext.getString(R.string.log_access_confirmation_title))
+            .setOnlyAlertOnce(true)
+            .setAutoCancel(true);
+        mNotificationManager.notify(notificationId, notificationBuilder.build());
+    }
+
+    /**
+     * A class which watches an uid for background access and notifies the logdMonitor when
+     * the package status becomes foreground (importance change)
+     */
+    private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
+        private final int mExpectedUid;
+        private final int mExpectedGid;
+        private final int mExpectedPid;
+        private final int mExpectedFd;
+        private int mExpectedImportance;
+        private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE;
+
+        UidImportanceListener(int uid, int gid, int pid, int fd, int importance) {
+            mExpectedUid = uid;
+            mExpectedGid = gid;
+            mExpectedPid = pid;
+            mExpectedFd = fd;
+            mExpectedImportance = importance;
+        }
+
+        @Override
+        public void onUidImportance(int uid, int importance) {
+            if (uid == mExpectedUid) {
+                mCurrentImportance = importance;
+
+                /**
+                 * 1) If the process status changes to foreground, send a notification
+                 * for user consent.
+                 * 2) If the process status remains background, we decline logd access request.
+                 **/
+                if (importance <= RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
+                    String clientInfo = getClientInfo(uid, mExpectedGid, mExpectedPid, mExpectedFd);
+                    sendNotification(0, clientInfo, uid, mExpectedGid, mExpectedPid,
+                            mExpectedFd);
+                    mActivityManager.removeOnUidImportanceListener(this);
+
+                    synchronized (LogcatManagerService.this) {
+                        sUidImportanceListenerCount--;
+                    }
+                } else {
+                    try {
+                        getLogdService().decline(uid, mExpectedGid, mExpectedPid, mExpectedFd);
+                    } catch (RemoteException ex) {
+                        Slog.e(TAG, "Fails to call remote functions ", ex);
+                    }
+                }
+            }
+        }
+    }
+
+    private static String getClientInfo(int uid, int gid, int pid, int fd) {
+        return "UID=" + Integer.toString(uid) + " GID=" + Integer.toString(gid) + " PID="
+            + Integer.toString(pid) + " FD=" + Integer.toString(fd);
     }
 
     private class LogdMonitor implements Runnable {
@@ -74,9 +318,7 @@
         }
 
         /**
-         * The current version grant the permission by default.
-         * And track the logd access.
-         * The next version will generate a prompt for users.
+         * LogdMonitor generates a prompt for users.
          * The users decide whether the logd access is allowed.
          */
         @Override
@@ -86,10 +328,61 @@
             }
 
             if (mStart) {
-                try {
-                    mLogdService.approve(mUid, mGid, mPid, mFd);
-                } catch (RemoteException ex) {
-                    Slog.e(TAG, "Fails to call remote functions ", ex);
+
+                // TODO See the comments of ALLOWABLE_TESTING_PACKAGES.
+                if (isAllowableTestingPackage(mUid)) {
+                    try {
+                        getLogdService().approve(mUid, mGid, mPid, mFd);
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                    return;
+                }
+
+                // If the access request is coming from adb shell, approve the logd access
+                if (mUid == AID_SHELL_UID) {
+                    try {
+                        getLogdService().approve(mUid, mGid, mPid, mFd);
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                    return;
+                }
+
+                final int procState = LocalServices.getService(ActivityManagerInternal.class)
+                        .getUidProcessState(mUid);
+                // If the process is foreground, send a notification for user consent
+                if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+                    String clientInfo = getClientInfo(mUid, mGid, mPid, mFd);
+                    sendNotification(0, clientInfo, mUid, mGid, mPid, mFd);
+                } else {
+                    /**
+                     * If the process is background, add a background process change listener and
+                     * monitor if the process status changes.
+                     * To avoid clients registering multiple listeners, we limit the number of
+                     * maximum listeners to MAX_UID_IMPORTANCE_COUNT_LISTENER.
+                     **/
+                    if (mActivityManager == null) {
+                        return;
+                    }
+
+                    synchronized (LogcatManagerService.this) {
+                        if (sUidImportanceListenerCount < MAX_UID_IMPORTANCE_COUNT_LISTENER) {
+                            // Trigger addOnUidImportanceListener when there is an update from
+                            // the importance of the process
+                            mActivityManager.addOnUidImportanceListener(new UidImportanceListener(
+                                    mUid, mGid, mPid, mFd,
+                                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE),
+                                    RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
+                            sUidImportanceListenerCount++;
+                        } else {
+                            try {
+                                getLogdService().decline(mUid, mGid, mPid, mFd);
+                            } catch (RemoteException e) {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
                 }
             }
         }
@@ -100,6 +393,8 @@
         mContext = context;
         mBinderService = new BinderService();
         mThreadExecutor = Executors.newCachedThreadPool();
+        mActivityManager = context.getSystemService(ActivityManager.class);
+        mNotificationManager = mContext.getSystemService(NotificationManager.class);
     }
 
     @Override
@@ -114,5 +409,4 @@
     private void addLogdService() {
         mLogdService = ILogd.Stub.asInterface(ServiceManager.getService("logd"));
     }
-
 }
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/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/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/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/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/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1167cb5..22c430f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -462,11 +462,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.
@@ -811,8 +806,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 +846,6 @@
                 return;
             }
 
-            if (mRenderShadowsInCompositorUri.equals(uri)) {
-                setShadowRenderer();
-                return;
-            }
-
             if (mDisplaySettingsPathUri.equals(uri)) {
                 updateDisplaySettingsLocation();
                 return;
@@ -972,11 +960,6 @@
         }
     }
 
-    private void setShadowRenderer() {
-        mRenderShadowsInCompositor = Settings.Global.getInt(mContext.getContentResolver(),
-                DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
-    }
-
     PowerManager mPowerManager;
     PowerManagerInternal mPowerManagerInternal;
 
@@ -1395,7 +1378,6 @@
         float[] spotColor = {0.f, 0.f, 0.f, spotShadowAlpha};
         SurfaceControl.setGlobalShadowSettings(ambientColor, spotColor, lightY, lightZ,
                 lightRadius);
-        setShadowRenderer();
     }
 
     /**
@@ -3855,14 +3837,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 +3864,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;
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/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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index d0c861f..c2dec06 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -154,6 +154,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 +225,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;
@@ -1392,7 +1393,6 @@
         DynamicSystemService dynamicSystem = null;
         IStorageManager storageManager = null;
         NetworkManagementService networkManagement = null;
-        IpSecService ipSecService = null;
         VpnManagerService vpnManager = null;
         VcnManagementService vcnManagement = null;
         NetworkStatsService networkStats = null;
@@ -1472,7 +1472,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 +1480,7 @@
 
             t.traceBegin("StartTelephonyRegistry");
             telephonyRegistry = new TelephonyRegistry(
-                context, new TelephonyRegistry.ConfigurationProvider());
+                    context, new TelephonyRegistry.ConfigurationProvider());
             ServiceManager.addService("telephony.registry", telephonyRegistry);
             t.traceEnd();
 
@@ -1897,15 +1897,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();
@@ -2792,7 +2783,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,15 +2874,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) {
@@ -3017,7 +2998,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 +3065,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);
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..7f57119 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;
@@ -746,6 +747,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 +760,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/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/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/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/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/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/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/telephony/java/android/telephony/ims/RcsClientConfiguration.java b/telephony/java/android/telephony/ims/RcsClientConfiguration.java
index c25ace0..f367e40 100644
--- a/telephony/java/android/telephony/ims/RcsClientConfiguration.java
+++ b/telephony/java/android/telephony/ims/RcsClientConfiguration.java
@@ -34,7 +34,7 @@
 
     /**@hide*/
     @StringDef(prefix = "RCS_PROFILE_",
-            value = {RCS_PROFILE_1_0, RCS_PROFILE_2_3})
+            value = {RCS_PROFILE_1_0, RCS_PROFILE_2_3, RCS_PROFILE_2_4})
     public @interface StringRcsProfile {}
 
     /**
@@ -45,6 +45,10 @@
      * RCS profile UP 2.3
      */
     public static final String RCS_PROFILE_2_3 = "UP_2.3";
+    /**
+     * RCS profile UP 2.4
+     */
+    public static final String RCS_PROFILE_2_4 = "UP_2.4";
 
     private String mRcsVersion;
     private String mRcsProfile;
@@ -58,8 +62,8 @@
      * @param rcsVersion The parameter identifies the RCS version supported
      * by the client. Refer to GSMA RCC.07 "rcs_version" parameter.
      * @param rcsProfile Identifies a fixed set of RCS services that are
-     * supported by the client. See {@link #RCS_PROFILE_1_0 } or
-     * {@link #RCS_PROFILE_2_3 }
+     * supported by the client. See {@link #RCS_PROFILE_1_0 },
+     * {@link #RCS_PROFILE_2_3 } or {@link #RCS_PROFILE_2_4 }
      * @param clientVendor Identifies the vendor providing the RCS client.
      * @param clientVersion Identifies the RCS client version. Refer to GSMA
      * RCC.07 "client_version" parameter.
@@ -80,8 +84,8 @@
      * @param rcsVersion The parameter identifies the RCS version supported
      * by the client. Refer to GSMA RCC.07 "rcs_version" parameter.
      * @param rcsProfile Identifies a fixed set of RCS services that are
-     * supported by the client. See {@link #RCS_PROFILE_1_0 } or
-     * {@link #RCS_PROFILE_2_3 }
+     * supported by the client. See {@link #RCS_PROFILE_1_0 },
+     * {@link #RCS_PROFILE_2_3 } or {@link #RCS_PROFILE_2_4 }
      * @param clientVendor Identifies the vendor providing the RCS client.
      * @param clientVersion Identifies the RCS client version. Refer to GSMA
      * RCC.07 "client_version" parameter.
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)
                 }