Merge "Treat GONE windows as READY for sync" into sc-v2-dev
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index db23a6d..c33d5ec 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -332,17 +332,20 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
                     for (int i = 0; i < schemaBundles.size(); i++) {
                         schemas.add(new AppSearchSchema(schemaBundles.get(i)));
@@ -359,7 +362,7 @@
                         }
                         schemasVisibleToPackages.put(entry.getKey(), packageIdentifiers);
                     }
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     SetSchemaResponse setSchemaResponse = instance.getAppSearchImpl().setSchema(
                             packageName,
                             databaseName,
@@ -418,15 +421,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     GetSchemaResponse response =
                             instance.getAppSearchImpl().getSchema(packageName, databaseName);
                     invokeCallbackOnResult(
@@ -450,15 +456,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     List<String> namespaces =
                             instance.getAppSearchImpl().getNamespaces(packageName, databaseName);
                     invokeCallbackOnResult(
@@ -485,20 +494,23 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchBatchResult.Builder<String, Void> resultBuilder =
                             new AppSearchBatchResult.Builder<>();
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     for (int i = 0; i < documentBundles.size(); i++) {
                         GenericDocument document = new GenericDocument(documentBundles.get(i));
                         try {
@@ -571,20 +583,23 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
                             new AppSearchBatchResult.Builder<>();
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     for (int i = 0; i < ids.size(); i++) {
                         String id = ids.get(i);
                         try {
@@ -652,18 +667,21 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     SearchResultPage searchResultPage = instance.getAppSearchImpl().query(
                             packageName,
                             databaseName,
@@ -718,18 +736,21 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
 
                     boolean callerHasSystemAccess =
                             instance.getVisibilityStore().doesCallerHaveSystemAccess(packageName);
@@ -783,17 +804,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
-            // TODO(b/162450968) check nextPageToken is being advanced by the same uid as originally
-            // opened it
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     SearchResultPage searchResultPage =
                             instance.getAppSearchImpl().getNextPage(packageName, nextPageToken);
                     invokeCallbackOnResult(
@@ -812,15 +834,18 @@
             Objects.requireNonNull(userHandle);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     instance.getAppSearchImpl().invalidateNextPageToken(packageName, nextPageToken);
                 } catch (Throwable t) {
                     Log.e(TAG, "Unable to invalidate the query page token", t);
@@ -846,15 +871,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     // we don't need to append the file. The file is always brand new.
                     try (DataOutputStream outputStream = new DataOutputStream(
                             new FileOutputStream(fileDescriptor.getFileDescriptor()))) {
@@ -895,15 +923,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
 
                     GenericDocument document;
                     ArrayList<Bundle> migrationFailureBundles = new ArrayList<>();
@@ -957,15 +988,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
 
                     if (systemUsage
                             && !instance.getVisibilityStore()
@@ -1004,20 +1038,23 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchBatchResult.Builder<String, Void> resultBuilder =
                             new AppSearchBatchResult.Builder<>();
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     for (int i = 0; i < ids.size(); i++) {
                         String id = ids.get(i);
                         try {
@@ -1090,18 +1127,21 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     instance.getAppSearchImpl().removeByQuery(
                             packageName,
                             databaseName,
@@ -1154,15 +1194,18 @@
             Objects.requireNonNull(callback);
 
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
                     AppSearchUserInstance instance =
-                            mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                            mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     StorageInfo storageInfo = instance.getAppSearchImpl()
                             .getStorageInfoForDatabase(packageName, databaseName);
                     Bundle storageInfoBundle = storageInfo.getBundle();
@@ -1184,18 +1227,21 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
                 AppSearchUserInstance instance = null;
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
-                    instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
                     instance.getAppSearchImpl().persistToDisk(PersistType.Code.FULL);
                     ++operationSuccessCount;
                 } catch (Throwable t) {
@@ -1236,7 +1282,6 @@
 
             long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
             int callingUid = Binder.getCallingUid();
-            UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
 
             EXECUTOR.execute(() -> {
                 @AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
@@ -1244,12 +1289,18 @@
                 int operationSuccessCount = 0;
                 int operationFailureCount = 0;
                 try {
-                    Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
-                    verifyUserUnlocked(callingUser);
-                    verifyCallingPackage(userContext, callingUser, callingUid, packageName);
-                    verifyNotInstantApp(userContext, packageName);
+                    verifyCaller(callingUid, packageName);
+
+                    // Obtain the user where the client wants to run the operations in. This should
+                    // end up being the same as userHandle, assuming it is not a special user and
+                    // the client is allowed to run operations in that user.
+                    UserHandle targetUser = handleIncomingUser(userHandle, callingUid);
+                    verifyUserUnlocked(targetUser);
+
+                    Context targetUserContext = mContext.createContextAsUser(targetUser,
+                            /*flags=*/ 0);
                     instance = mAppSearchUserInstanceManager.getOrCreateUserInstance(
-                            userContext, callingUser, AppSearchConfig.getInstance(EXECUTOR));
+                            targetUserContext, targetUser, AppSearchConfig.getInstance(EXECUTOR));
                     ++operationSuccessCount;
                     invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
                 } catch (Throwable t) {
@@ -1278,29 +1329,6 @@
             });
         }
 
-        private void verifyCallingPackage(
-                @NonNull Context userContext,
-                @NonNull UserHandle actualCallingUser,
-                int actualCallingUid,
-                @NonNull String claimedCallingPackage) {
-            Objects.requireNonNull(actualCallingUser);
-            Objects.requireNonNull(claimedCallingPackage);
-
-            int claimedCallingUid = PackageUtil.getPackageUid(
-                    userContext, claimedCallingPackage);
-            if (claimedCallingUid == INVALID_UID) {
-                throw new SecurityException(
-                        "Specified calling package [" + claimedCallingPackage + "] not found");
-            }
-            if (claimedCallingUid != actualCallingUid) {
-                throw new SecurityException(
-                        "Specified calling package ["
-                                + claimedCallingPackage
-                                + "] does not match the calling uid "
-                                + actualCallingUid);
-            }
-        }
-
         /** Invokes the {@link IAppSearchResultCallback} with the result. */
         private void invokeCallbackOnResult(
                 IAppSearchResultCallback callback, AppSearchResult<?> result) {
@@ -1354,33 +1382,72 @@
     /**
      * Helper for dealing with incoming user arguments to system service calls.
      *
-     * @param requestedUser The user which the caller is requesting to execute as.
+     * @param targetUserHandle The user which the caller is requesting to execute as.
      * @param callingUid The actual uid of the caller as determined by Binder.
      * @return the user handle that the call should run as. Will always be a concrete user.
      */
     @NonNull
-    private UserHandle handleIncomingUser(@NonNull UserHandle requestedUser, int callingUid) {
-        UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
-        if (callingUser.equals(requestedUser)) {
-            return requestedUser;
+    private UserHandle handleIncomingUser(@NonNull UserHandle targetUserHandle, int callingUid) {
+        UserHandle callingUserHandle = UserHandle.getUserHandleForUid(callingUid);
+        if (callingUserHandle.equals(targetUserHandle)) {
+            return targetUserHandle;
         }
 
         // Duplicates UserController#ensureNotSpecialUser
-        if (requestedUser.getIdentifier() < 0) {
+        if (targetUserHandle.getIdentifier() < 0) {
             throw new IllegalArgumentException(
-                    "Call does not support special user " + requestedUser);
+                    "Call does not support special user " + targetUserHandle);
         }
 
         throw new SecurityException(
-                "Requested user, " + requestedUser + ", is not the same as the calling user, "
-                        + callingUser + ".");
+                "Requested user, " + targetUserHandle + ", is not the same as the calling user, "
+                        + callingUserHandle + ".");
     }
 
     /**
-     * Helper for ensuring instant apps can't make calls to AppSearch.
+     * Verify various aspects of the calling user.
      *
-     * @param userContext Context of the user making the call.
-     * @param packageName Package name of the caller.
+     * @param callingUid Uid of the caller, usually retrieved from Binder for authenticity.
+     * @param claimedCallingPackage Package name the caller claims to be.
+     */
+    private void verifyCaller(int callingUid, @NonNull String claimedCallingPackage) {
+        // Obtain the user where the client is running in. Note that this could be different from
+        // the userHandle where the client wants to run the AppSearch operation in.
+        UserHandle callingUserHandle = UserHandle.getUserHandleForUid(callingUid);
+        Context callingUserContext = mContext.createContextAsUser(callingUserHandle,
+                /*flags=*/ 0);
+
+        verifyCallingPackage(callingUserContext, callingUid, claimedCallingPackage);
+        verifyNotInstantApp(callingUserContext, claimedCallingPackage);
+    }
+
+    /**
+     * Check that the caller's supposed package name matches the uid making the call.
+     *
+     * @throws SecurityException if the package name and uid don't match.
+     */
+    private void verifyCallingPackage(
+            @NonNull Context actualCallingUserContext,
+            int actualCallingUid,
+            @NonNull String claimedCallingPackage) {
+        int claimedCallingUid = PackageUtil.getPackageUid(
+                actualCallingUserContext, claimedCallingPackage);
+        if (claimedCallingUid == INVALID_UID) {
+            throw new SecurityException(
+                    "Specified calling package [" + claimedCallingPackage + "] not found");
+        }
+        if (claimedCallingUid != actualCallingUid) {
+            throw new SecurityException(
+                    "Specified calling package ["
+                            + claimedCallingPackage
+                            + "] does not match the calling uid "
+                            + actualCallingUid);
+        }
+    }
+
+    /**
+     * Ensure instant apps can't make calls to AppSearch.
+     *
      * @throws SecurityException if the caller is an instant app.
      */
     private void verifyNotInstantApp(@NonNull Context userContext, @NonNull String packageName) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index f212b6d..ae812ec 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -530,8 +530,9 @@
         // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be
         // used without security checks
         public IBinder shareableActivityToken;
-        // The token of the TaskFragment that embedded this activity.
-        @Nullable public IBinder mTaskFragmentToken;
+        // The token of the initial TaskFragment that embedded this activity. Do not rely on it
+        // after creation because the activity could be reparented.
+        @Nullable public IBinder mInitialTaskFragmentToken;
         int ident;
         @UnsupportedAppUsage
         Intent intent;
@@ -626,7 +627,7 @@
                 boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
                 IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments,
                 IBinder shareableActivityToken, boolean launchedFromBubble,
-                IBinder taskFragmentToken) {
+                IBinder initialTaskFragmentToken) {
             this.token = token;
             this.assistToken = assistToken;
             this.shareableActivityToken = shareableActivityToken;
@@ -648,7 +649,7 @@
             mActivityOptions = activityOptions;
             mPendingFixedRotationAdjustments = fixedRotationAdjustments;
             mLaunchedFromBubble = launchedFromBubble;
-            mTaskFragmentToken = taskFragmentToken;
+            mInitialTaskFragmentToken = initialTaskFragmentToken;
             init();
         }
 
diff --git a/core/java/android/appwidget/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java
index 5694ca8..266e33a 100644
--- a/core/java/android/appwidget/AppWidgetManagerInternal.java
+++ b/core/java/android/appwidget/AppWidgetManagerInternal.java
@@ -19,6 +19,8 @@
 import android.annotation.Nullable;
 import android.util.ArraySet;
 
+import java.util.Set;
+
 /**
  * App widget manager local system service interface.
  *
@@ -42,4 +44,16 @@
      * @param userId The user that is being unlocked.
      */
     public abstract void unlockUser(int userId);
+
+    /**
+     * Updates all widgets, applying changes to Runtime Resource Overlay affecting the specified
+     * target packages.
+     *
+     * @param packageNames The names of all target packages for which an overlay was modified
+     * @param userId The user for which overlay modifications occurred.
+     * @param updateFrameworkRes Whether or not an overlay affected the values of framework
+     *                           resources.
+     */
+    public abstract void applyResourceOverlaysToWidgets(Set<String> packageNames, int userId,
+            boolean updateFrameworkRes);
 }
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index abcc33c..4f20553 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -21,6 +21,7 @@
 import android.graphics.Point;
 import android.hardware.SensorManager;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.PowerManager;
 import android.util.IntArray;
 import android.util.Slog;
@@ -340,6 +341,28 @@
     public abstract List<RefreshRateLimitation> getRefreshRateLimitations(int displayId);
 
     /**
+     * Returns the window token of the level of the WindowManager hierarchy to mirror. Returns null
+     * if layer mirroring by SurfaceFlinger should not be performed for the given displayId.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    public abstract IBinder getWindowTokenClientToMirror(int displayId);
+
+    /**
+     * For the given displayId, updates the window token of the level of the WindowManager hierarchy
+     * to mirror. If windowToken is null, then SurfaceFlinger performs no layer mirroring to the
+     * given display.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    public abstract void setWindowTokenClientToMirror(int displayId, IBinder windowToken);
+
+    /**
+     * Returns the default size of the surface associated with the display, or null if the surface
+     * is not provided for layer mirroring by SurfaceFlinger.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    public abstract Point getDisplaySurfaceDefaultSize(int displayId);
+
+    /**
      * Describes the requested power state of the display.
      *
      * This object is intended to describe the general characteristics of the
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java
index 71688c7c..0e86f43 100644
--- a/core/java/android/hardware/display/VirtualDisplayConfig.java
+++ b/core/java/android/hardware/display/VirtualDisplayConfig.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.media.projection.MediaProjection;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.Surface;
@@ -91,9 +92,16 @@
      */
     private int mDisplayIdToMirror = DEFAULT_DISPLAY;
 
+    /**
+     * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring
+     * should not be performed.
+     */
+    @Nullable
+    private IBinder mWindowTokenClientToMirror = null;
 
 
-    // Code below generated by codegen v1.0.20.
+
+    // Code below generated by codegen v1.0.23.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -115,7 +123,8 @@
             int flags,
             @Nullable Surface surface,
             @Nullable String uniqueId,
-            int displayIdToMirror) {
+            int displayIdToMirror,
+            @Nullable IBinder windowTokenClientToMirror) {
         this.mName = name;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mName);
@@ -135,6 +144,7 @@
         this.mSurface = surface;
         this.mUniqueId = uniqueId;
         this.mDisplayIdToMirror = displayIdToMirror;
+        this.mWindowTokenClientToMirror = windowTokenClientToMirror;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -212,6 +222,15 @@
         return mDisplayIdToMirror;
     }
 
+    /**
+     * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring
+     * should not be performed.
+     */
+    @DataClass.Generated.Member
+    public @Nullable IBinder getWindowTokenClientToMirror() {
+        return mWindowTokenClientToMirror;
+    }
+
     @Override
     @DataClass.Generated.Member
     public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -221,6 +240,7 @@
         int flg = 0;
         if (mSurface != null) flg |= 0x20;
         if (mUniqueId != null) flg |= 0x40;
+        if (mWindowTokenClientToMirror != null) flg |= 0x100;
         dest.writeInt(flg);
         dest.writeString(mName);
         dest.writeInt(mWidth);
@@ -230,6 +250,7 @@
         if (mSurface != null) dest.writeTypedObject(mSurface, flags);
         if (mUniqueId != null) dest.writeString(mUniqueId);
         dest.writeInt(mDisplayIdToMirror);
+        if (mWindowTokenClientToMirror != null) dest.writeStrongBinder(mWindowTokenClientToMirror);
     }
 
     @Override
@@ -252,6 +273,7 @@
         Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR);
         String uniqueId = (flg & 0x40) == 0 ? null : in.readString();
         int displayIdToMirror = in.readInt();
+        IBinder windowTokenClientToMirror = (flg & 0x100) == 0 ? null : (IBinder) in.readStrongBinder();
 
         this.mName = name;
         com.android.internal.util.AnnotationValidations.validate(
@@ -272,6 +294,7 @@
         this.mSurface = surface;
         this.mUniqueId = uniqueId;
         this.mDisplayIdToMirror = displayIdToMirror;
+        this.mWindowTokenClientToMirror = windowTokenClientToMirror;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -305,6 +328,7 @@
         private @Nullable Surface mSurface;
         private @Nullable String mUniqueId;
         private int mDisplayIdToMirror;
+        private @Nullable IBinder mWindowTokenClientToMirror;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -439,10 +463,22 @@
             return this;
         }
 
+        /**
+         * The window token of the level of the WindowManager hierarchy to mirror, or null if mirroring
+         * should not be performed.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setWindowTokenClientToMirror(@NonNull IBinder value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x100;
+            mWindowTokenClientToMirror = value;
+            return this;
+        }
+
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull VirtualDisplayConfig build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x100; // Mark builder used
+            mBuilderFieldsSet |= 0x200; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x10) == 0) {
                 mFlags = 0;
@@ -456,6 +492,9 @@
             if ((mBuilderFieldsSet & 0x80) == 0) {
                 mDisplayIdToMirror = DEFAULT_DISPLAY;
             }
+            if ((mBuilderFieldsSet & 0x100) == 0) {
+                mWindowTokenClientToMirror = null;
+            }
             VirtualDisplayConfig o = new VirtualDisplayConfig(
                     mName,
                     mWidth,
@@ -464,12 +503,13 @@
                     mFlags,
                     mSurface,
                     mUniqueId,
-                    mDisplayIdToMirror);
+                    mDisplayIdToMirror,
+                    mWindowTokenClientToMirror);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x100) != 0) {
+            if ((mBuilderFieldsSet & 0x200) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -477,10 +517,10 @@
     }
 
     @DataClass.Generated(
-            time = 1604456298440L,
-            codegenVersion = "1.0.20",
+            time = 1620657851981L,
+            codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java",
-            inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate  int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate  int mDisplayIdToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
+            inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate  int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate  int mDisplayIdToMirror\nprivate @android.annotation.Nullable android.os.IBinder mWindowTokenClientToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ff2d2eb..aaf53ee 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -29,6 +29,7 @@
 import android.graphics.ColorSpace;
 import android.graphics.HardwareRenderer;
 import android.graphics.Matrix;
+import android.graphics.Point;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RenderNode;
@@ -408,6 +409,20 @@
     }
 
     /**
+     * Returns the default size of this Surface provided by the consumer of the surface.
+     * Should only be used by the producer of the surface.
+     *
+     * @hide
+     */
+    @NonNull
+    public Point getDefaultSize() {
+        synchronized (mLock) {
+            checkNotReleasedLocked();
+            return new Point(nativeGetWidth(mNativeObject), nativeGetHeight(mNativeObject));
+        }
+    }
+
+    /**
      * Gets a {@link Canvas} for drawing into this surface.
      *
      * After drawing into the provided {@link Canvas}, the caller must
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 27eb2a5..7d75d99 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -9931,7 +9931,10 @@
         if (!mUseMTRenderer) {
             return;
         }
-        mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
+        // Only wait if it will report next draw.
+        if (mReportNextDraw) {
+            mWindowDrawCountDown = new CountDownLatch(mWindowCallbacks.size());
+        }
         for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
             mWindowCallbacks.get(i).onRequestDraw(mReportNextDraw);
         }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index e827f0a..91fc5a5 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -5824,6 +5824,25 @@
         return false;
     }
 
+    /** @hide */
+    public void updateAppInfo(@NonNull ApplicationInfo info) {
+        if (mApplication != null && mApplication.sourceDir.equals(info.sourceDir)) {
+            // Overlay paths are generated against a particular version of an application.
+            // The overlays paths of a newly upgraded application are incompatible with the
+            // old version of the application.
+            mApplication = info;
+        }
+        if (hasSizedRemoteViews()) {
+            for (RemoteViews layout : mSizedRemoteViews) {
+                layout.updateAppInfo(info);
+            }
+        }
+        if (hasLandscapeAndPortraitLayouts()) {
+            mLandscape.updateAppInfo(info);
+            mPortrait.updateAppInfo(info);
+        }
+    }
+
     private Context getContextForResources(Context context) {
         if (mApplication != null) {
             if (context.getUserId() == UserHandle.getUserId(mApplication.uid)
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 1c5b39e..702a8ba 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -352,6 +352,7 @@
         private final Rect mEndAbsBounds = new Rect();
         private final Point mEndRelOffset = new Point();
         private ActivityManager.RunningTaskInfo mTaskInfo = null;
+        private boolean mAllowEnterPip;
         private int mStartRotation = ROTATION_UNDEFINED;
         private int mEndRotation = ROTATION_UNDEFINED;
         private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
@@ -372,6 +373,7 @@
             mEndAbsBounds.readFromParcel(in);
             mEndRelOffset.readFromParcel(in);
             mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+            mAllowEnterPip = in.readBoolean();
             mStartRotation = in.readInt();
             mEndRotation = in.readInt();
             mRotationAnimation = in.readInt();
@@ -415,6 +417,11 @@
             mTaskInfo = taskInfo;
         }
 
+        /** Sets the allowEnterPip flag which represents AppOpsManager check on PiP permission */
+        public void setAllowEnterPip(boolean allowEnterPip) {
+            mAllowEnterPip = allowEnterPip;
+        }
+
         /** Sets the start and end rotation of this container. */
         public void setRotation(@Surface.Rotation int start, @Surface.Rotation int end) {
             mStartRotation = start;
@@ -492,6 +499,10 @@
             return mTaskInfo;
         }
 
+        public boolean getAllowEnterPip() {
+            return mAllowEnterPip;
+        }
+
         public int getStartRotation() {
             return mStartRotation;
         }
@@ -517,6 +528,7 @@
             mEndAbsBounds.writeToParcel(dest, flags);
             mEndRelOffset.writeToParcel(dest, flags);
             dest.writeTypedObject(mTaskInfo, flags);
+            dest.writeBoolean(mAllowEnterPip);
             dest.writeInt(mStartRotation);
             dest.writeInt(mEndRotation);
             dest.writeInt(mRotationAnimation);
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 8765659..789e279 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -57,7 +57,7 @@
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"შემომავალი ზარის აბონენტის ID"</string>
-    <string name="ClirMmi" msgid="6752346475055446417">"გამავალი აბონენტის ID-ის დამალვა"</string>
+    <string name="ClirMmi" msgid="6752346475055446417">"გამავალი აბონენტის ID-ს დამალვა"</string>
     <string name="ColpMmi" msgid="4736462893284419302">"დაუკავშირდა Line ID-ს"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"დაუკავშირდა Line ID Restriction-ს"</string>
     <string name="CfMmi" msgid="8390012691099787178">"ზარის გადამისამართება"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 81be9a7..1d2fd8a 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -247,21 +247,21 @@
     <string name="global_action_power_options" msgid="1185286119330160073">"పవర్"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"రీస్టార్ట్ చేయి"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"ఎమర్జెన్సీ"</string>
-    <string name="global_action_bug_report" msgid="5127867163044170003">"బగ్ నివేదిక"</string>
+    <string name="global_action_bug_report" msgid="5127867163044170003">"బగ్ రిపోర్ట్‌"</string>
     <string name="global_action_logout" msgid="6093581310002476511">"సెషన్‌ను ముగించు"</string>
     <string name="global_action_screenshot" msgid="2610053466156478564">"స్క్రీన్‌షాట్"</string>
     <string name="bugreport_title" msgid="8549990811777373050">"బగ్ రిపోర్ట్‌"</string>
-    <string name="bugreport_message" msgid="5212529146119624326">"ఇది ఇ-మెయిల్ సందేశం రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ నివేదికను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
-    <string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ప్రభావశీల నివేదిక"</string>
-    <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"చాలా సందర్భాల్లో దీన్ని ఉపయోగించండి. ఇది నివేదిక ప్రోగ్రెస్‌ను ట్రాక్ చేయడానికి, సమస్య గురించి మరిన్ని వివరాలను నమోదు చేయడానికి మరియు స్క్రీన్‌షాట్‌లు తీయడానికి మిమ్మల్ని అనుమతిస్తుంది. ఇది నివేదించడానికి ఎక్కువ సమయం పట్టే తక్కువ వినియోగ విభాగాలను విడిచిపెట్టవచ్చు."</string>
-    <string name="bugreport_option_full_title" msgid="7681035745950045690">"పూర్తి నివేదిక"</string>
-    <string name="bugreport_option_full_summary" msgid="1975130009258435885">"మీ పరికరం ప్రతిస్పందనరహితంగా ఉన్నప్పుడు లేదా చాలా నెమ్మదిగా ఉన్నప్పుడు లేదా మీకు అన్ని నివేదిక విభాగాలు అవసరమైనప్పుడు సిస్టమ్‌కి అంతరాయ స్థాయి కనిష్టంగా ఉండేలా చేయడానికి ఈ ఎంపిక ఉపయోగించండి. ఇది మరిన్ని వివరాలను నమోదు చేయడానికి లేదా అదనపు స్క్రీన్‌షాట్‌లు తీయడానికి మిమ్మల్ని అనుమతించదు."</string>
+    <string name="bugreport_message" msgid="5212529146119624326">"ఇది ఇ-మెయిల్ సందేశం రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ రిపోర్ట్‌ను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
+    <string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ప్రభావశీల రిపోర్ట్‌"</string>
+    <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"చాలా సందర్భాల్లో దీన్ని ఉపయోగించండి. ఇది రిపోర్ట్‌ ప్రోగ్రెస్‌ను ట్రాక్ చేయడానికి, సమస్య గురించి మరిన్ని వివరాలను నమోదు చేయడానికి మరియు స్క్రీన్‌షాట్‌లు తీయడానికి మిమ్మల్ని అనుమతిస్తుంది. ఇది నివేదించడానికి ఎక్కువ సమయం పట్టే తక్కువ వినియోగ విభాగాలను విడిచిపెట్టవచ్చు."</string>
+    <string name="bugreport_option_full_title" msgid="7681035745950045690">"పూర్తి రిపోర్ట్‌"</string>
+    <string name="bugreport_option_full_summary" msgid="1975130009258435885">"మీ పరికరం ప్రతిస్పందనరహితంగా ఉన్నప్పుడు లేదా చాలా నెమ్మదిగా ఉన్నప్పుడు లేదా మీకు అన్ని రిపోర్ట్‌ విభాగాలు అవసరమైనప్పుడు సిస్టమ్‌కి అంతరాయ స్థాయి కనిష్టంగా ఉండేలా చేయడానికి ఈ ఎంపిక ఉపయోగించండి. ఇది మరిన్ని వివరాలను నమోదు చేయడానికి లేదా అదనపు స్క్రీన్‌షాట్‌లు తీయడానికి మిమ్మల్ని అనుమతించదు."</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="3906120379260059206">
-      <item quantity="other">బగ్ నివేదిక కోసం <xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
-      <item quantity="one">బగ్ నివేదిక కోసం <xliff:g id="NUMBER_0">%d</xliff:g> సెకనులో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
+      <item quantity="other">బగ్ రిపోర్ట్‌ కోసం <xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
+      <item quantity="one">బగ్ రిపోర్ట్‌ కోసం <xliff:g id="NUMBER_0">%d</xliff:g> సెకనులో స్క్రీన్‌షాట్ తీయబోతోంది.</item>
     </plurals>
-    <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"బగ్ నివేదికతో ఉన్న స్క్రీన్‌షాట్ తీయబడింది"</string>
-    <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"బగ్ నివేదికతో ఉన్న స్క్రీన్‌షాట్‌ను తీయడం విఫలమైంది"</string>
+    <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"బగ్ రిపోర్ట్‌తో ఉన్న స్క్రీన్‌షాట్ తీయబడింది"</string>
+    <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"బగ్ రిపోర్ట్‌తో ఉన్న స్క్రీన్‌షాట్‌ను తీయడం విఫలమైంది"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"నిశ్శబ్ద మోడ్"</string>
     <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"ధ్వని ఆఫ్‌లో ఉంది"</string>
     <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"ధ్వని ఆన్‌లో ఉంది"</string>
@@ -1384,10 +1384,10 @@
     <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"USB పోర్ట్ ఆటోమేటిక్‌గా నిలిపివేయబడింది. మరింత తెలుసుకోవడానికి నొక్కండి."</string>
     <string name="usb_contaminant_not_detected_title" msgid="2651167729563264053">"USB పోర్ట్‌ను ఉపయోగించడం సురక్షితం"</string>
     <string name="usb_contaminant_not_detected_message" msgid="892863190942660462">"ఫోన్ ఇకపై ద్రవ లేదా వ్యర్థ పదార్థాలను గుర్తించదు."</string>
-    <string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"బగ్ నివేదికను తీస్తోంది…"</string>
-    <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"బగ్ నివేదికను భాగస్వామ్యం చేయాలా?"</string>
-    <string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"బగ్ నివేదికను భాగస్వామ్యం చేస్తోంది..."</string>
-    <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"మీ నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ నివేదికను అభ్యర్థించారు. యాప్‌లు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
+    <string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"బగ్ రిపోర్ట్‌ను తీస్తోంది…"</string>
+    <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"బగ్ రిపోర్ట్‌ను భాగస్వామ్యం చేయాలా?"</string>
+    <string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"బగ్ రిపోర్ట్‌ను భాగస్వామ్యం చేస్తోంది..."</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"మీ నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ రిపోర్ట్‌ను అభ్యర్థించారు. యాప్‌లు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
     <string name="share_remote_bugreport_action" msgid="7630880678785123682">"షేర్ చేయి"</string>
     <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"తిరస్కరిస్తున్నాను"</string>
     <string name="select_input_method" msgid="3971267998568587025">"ఇన్‌పుట్ పద్ధతిని ఎంచుకోండి"</string>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 51bf6d53..42e470b 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -255,12 +255,6 @@
             | FILTER_BITMAP_FLAG;
 
     /**
-     * These flags are always set on a reset paint or a new paint instantiated using
-     * {@link #Paint()}.
-     */
-    private static final int DEFAULT_PAINT_FLAGS = ANTI_ALIAS_FLAG | DITHER_FLAG;
-
-    /**
      * Font hinter option that disables font hinting.
      *
      * @see #setHinting(int)
@@ -577,12 +571,12 @@
      * On devices running {@link Build.VERSION_CODES#Q} and above,
      * {@code FILTER_BITMAP_FLAG} is set by this constructor, and it can be
      * cleared with {@link #setFlags} or {@link #setFilterBitmap}.
-     * On devices running {@link Build.VERSION_CODES#S} and above, {@code ANTI_ALIAS_FLAG} and
-     * {@code DITHER_FLAG} are set by this constructor, and they can be cleared with
-     * {@link #setFlags} or {@link #setAntiAlias} and {@link #setDither}, respectively.</p>
+     * On devices running {@link Build.VERSION_CODES#S} and above, {@code ANTI_ALIAS_FLAG}
+     * is set by this constructor, and it can be cleared with {@link #setFlags} or
+     * {@link #setAntiAlias}.</p>
      */
     public Paint() {
-        this(DEFAULT_PAINT_FLAGS);
+        this(ANTI_ALIAS_FLAG);
     }
 
     /**
@@ -627,7 +621,7 @@
     /** Restores the paint to its default settings. */
     public void reset() {
         nReset(mNativePaint);
-        setFlags(HIDDEN_DEFAULT_PAINT_FLAGS | DEFAULT_PAINT_FLAGS);
+        setFlags(HIDDEN_DEFAULT_PAINT_FLAGS | ANTI_ALIAS_FLAG);
 
         // TODO: Turning off hinting has undesirable side effects, we need to
         //       revisit hinting once we add support for subpixel positioning
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
index 912c61b..802976f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
@@ -270,7 +270,7 @@
     private TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken,
             Activity activityToAdd) {
         final IBinder taskFragmentToken = ActivityThread.currentActivityThread().getActivityClient(
-                activityToken).mTaskFragmentToken;
+                activityToken).mInitialTaskFragmentToken;
         for (TaskFragmentContainer container : mContainers) {
             if (container.hasActivity(activityToken)) {
                 return container;
diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
index 7658fca..0cf6d73 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
@@ -17,7 +17,7 @@
 <com.android.wm.shell.common.AlphaOptimizedButton
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@android:style/Widget.DeviceDefault.Button.Borderless"
-    android:id="@+id/settings_button"
+    android:id="@+id/manage_button"
     android:layout_gravity="start"
     android:layout_width="wrap_content"
     android:layout_height="@dimen/bubble_manage_button_height"
diff --git a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
index fd4c3ba..87deb8b 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
@@ -21,7 +21,6 @@
     android:layout_width="wrap_content"
     android:paddingTop="48dp"
     android:paddingBottom="48dp"
-    android:paddingStart="@dimen/bubble_stack_user_education_side_inset"
     android:paddingEnd="16dp"
     android:layout_marginEnd="24dp"
     android:orientation="vertical"
diff --git a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
index c5c42fc..fafe40e 100644
--- a/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
@@ -23,7 +23,6 @@
     android:clickable="true"
     android:paddingTop="28dp"
     android:paddingBottom="16dp"
-    android:paddingStart="@dimen/bubble_expanded_view_padding"
     android:paddingEnd="48dp"
     android:layout_marginEnd="24dp"
     android:orientation="vertical"
@@ -66,27 +65,21 @@
         android:id="@+id/button_layout"
         android:orientation="horizontal" >
 
-        <com.android.wm.shell.common.AlphaOptimizedButton
-            style="@android:style/Widget.Material.Button.Borderless"
-            android:id="@+id/manage"
-            android:layout_gravity="start"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:focusable="true"
-            android:clickable="false"
-            android:text="@string/manage_bubbles_text"
-            android:textColor="@android:color/system_neutral1_900"
+        <include
+            layout="@layout/bubble_manage_button"
             />
 
         <com.android.wm.shell.common.AlphaOptimizedButton
-            style="@android:style/Widget.Material.Button.Borderless"
+            style="@android:style/Widget.DeviceDefault.Button.Borderless"
             android:id="@+id/got_it"
             android:layout_gravity="start"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_height="@dimen/bubble_manage_button_height"
             android:focusable="true"
             android:text="@string/bubbles_user_education_got_it"
+            android:textSize="@*android:dimen/text_size_body_2_material"
             android:textColor="@android:color/system_neutral1_900"
+            android:background="@drawable/bubble_manage_btn_bg"
             />
     </LinearLayout>
 </LinearLayout>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 7da31aa..130f741 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -124,7 +124,7 @@
          should also be updated. -->
     <dimen name="bubble_expanded_default_height">180dp</dimen>
     <!-- On large screens the width of the expanded view is restricted to this size. -->
-    <dimen name="bubble_expanded_view_tablet_width">412dp</dimen>
+    <dimen name="bubble_expanded_view_phone_landscape_overflow_width">412dp</dimen>
     <!-- Inset to apply to the icon in the overflow button. -->
     <dimen name="bubble_overflow_icon_inset">30dp</dimen>
     <!-- Default (and minimum) height of bubble overflow -->
@@ -184,14 +184,8 @@
     <dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
     <dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
     <dimen name="bubble_manage_menu_elevation">4dp</dimen>
-
-    <!-- Bubbles user education views -->
-    <dimen name="bubbles_manage_education_width">160dp</dimen>
-    <!-- The inset from the top bound of the manage button to place the user education. -->
-    <dimen name="bubbles_manage_education_top_inset">65dp</dimen>
-    <!-- Size of padding for the user education cling, this should at minimum be larger than
-        individual_bubble_size + some padding. -->
-    <dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
+    <!-- Size of user education views on large screens (phone is just match parent). -->
+    <dimen name="bubbles_user_education_width_large_screen">400dp</dimen>
 
     <!-- The width/height of the size compat restart button. -->
     <dimen name="size_compat_button_size">48dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index 9bbede3..df4f238 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -20,7 +20,9 @@
 
 import com.android.wm.shell.apppairs.AppPairsController;
 import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.draganddrop.DragAndDropController;
@@ -39,7 +41,9 @@
 public class ShellInitImpl {
     private static final String TAG = ShellInitImpl.class.getSimpleName();
 
+    private final DisplayController mDisplayController;
     private final DisplayImeController mDisplayImeController;
+    private final DisplayInsetsController mDisplayInsetsController;
     private final DragAndDropController mDragAndDropController;
     private final ShellTaskOrganizer mShellTaskOrganizer;
     private final Optional<BubbleController> mBubblesOptional;
@@ -55,7 +59,10 @@
 
     private final InitImpl mImpl = new InitImpl();
 
-    public ShellInitImpl(DisplayImeController displayImeController,
+    public ShellInitImpl(
+            DisplayController displayController,
+            DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController,
             DragAndDropController dragAndDropController,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<BubbleController> bubblesOptional,
@@ -68,7 +75,9 @@
             Transitions transitions,
             StartingWindowController startingWindow,
             ShellExecutor mainExecutor) {
+        mDisplayController = displayController;
         mDisplayImeController = displayImeController;
+        mDisplayInsetsController = displayInsetsController;
         mDragAndDropController = dragAndDropController;
         mShellTaskOrganizer = shellTaskOrganizer;
         mBubblesOptional = bubblesOptional;
@@ -88,7 +97,9 @@
     }
 
     private void init() {
-        // Start listening for display changes
+        // Start listening for display and insets changes
+        mDisplayController.initialize();
+        mDisplayInsetsController.initialize();
         mDisplayImeController.startMonitorDisplays();
 
         // Setup the shell organizer
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index 8aca01d..2aead93 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -62,4 +62,10 @@
      */
     public static final Interpolator PANEL_CLOSE_ACCELERATED =
             new PathInterpolator(0.3f, 0, 0.5f, 1);
+
+    public static final PathInterpolator SLOWDOWN_INTERPOLATOR =
+            new PathInterpolator(0.5f, 1f, 0.5f, 1f);
+
+    public static final PathInterpolator DIM_INTERPOLATOR =
+            new PathInterpolator(.23f, .87f, .52f, -0.11f);
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index e7764ea..95b80df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -636,10 +636,16 @@
         }
     }
 
-    /** For the overflow to be focusable & receive key events the flags must be update. **/
-    void updateWindowFlagsForOverflow(boolean showingOverflow) {
+    /**
+     * In some situations bubble's should be able to receive key events for back:
+     * - when the bubble overflow is showing
+     * - when the user education for the stack is showing.
+     *
+     * @param interceptBack whether back should be intercepted or not.
+     */
+    void updateWindowFlagsForBackpress(boolean interceptBack) {
         if (mStackView != null && mAddedToWindowManager) {
-            mWmLayoutParams.flags = showingOverflow
+            mWmLayoutParams.flags = interceptBack
                     ? 0
                     : WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 252b588..4ac7dcf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -228,7 +228,7 @@
         @Override
         public void onBackPressedOnTaskRoot(int taskId) {
             if (mTaskId == taskId && mStackView.isExpanded()) {
-                mController.collapseStack();
+                mStackView.onBackPressed();
             }
         }
     };
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index ede4228..5e9d97f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -142,7 +142,7 @@
         super.onAttachedToWindow();
         if (mController != null) {
             // For the overflow to get key events (e.g. back press) we need to adjust the flags
-            mController.updateWindowFlagsForOverflow(true);
+            mController.updateWindowFlagsForBackpress(true);
         }
         setOnKeyListener(mKeyListener);
     }
@@ -151,7 +151,7 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         if (mController != null) {
-            mController.updateWindowFlagsForOverflow(false);
+            mController.updateWindowFlagsForBackpress(false);
         }
         setOnKeyListener(null);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index df804ec..7d4fb21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -65,7 +65,8 @@
     public static final float FLYOUT_MAX_WIDTH_PERCENT_LARGE_SCREEN = 0.3f;
     /** The max percent of screen width to use for the flyout on phone. */
     public static final float FLYOUT_MAX_WIDTH_PERCENT = 0.6f;
-
+    /** The percent of screen width that should be used for the expanded view on a large screen. **/
+    public static final float EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT = 0.72f;
 
     private Context mContext;
     private WindowManager mWindowManager;
@@ -78,7 +79,8 @@
 
     private int mBubbleSize;
     private int mSpacingBetweenBubbles;
-    private int mExpandedViewLargeScreenWidth;
+    private float mExpandedViewLargeScreenWidth;
+    private int mOverflowWidth;
     private int mExpandedViewPadding;
     private int mPointerMargin;
     private int mPointerWidth;
@@ -166,9 +168,11 @@
         mBubbleSize = res.getDimensionPixelSize(R.dimen.bubble_size);
         mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
         mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
-
-        mExpandedViewLargeScreenWidth = res.getDimensionPixelSize(
-                R.dimen.bubble_expanded_view_tablet_width);
+        mExpandedViewLargeScreenWidth = bounds.width() * EXPANDED_VIEW_LARGE_SCREEN_WIDTH_PERCENT;
+        mOverflowWidth = mIsLargeScreen
+                ? (int) mExpandedViewLargeScreenWidth
+                : res.getDimensionPixelSize(
+                        R.dimen.bubble_expanded_view_phone_landscape_overflow_width);
         mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
         mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
         mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
@@ -242,6 +246,13 @@
     }
 
     /**
+     * @return a rect of the screen size.
+     */
+    public Rect getScreenRect() {
+        return mScreenRect;
+    }
+
+    /**
      * @return the relevant insets (status bar, nav bar, cutouts). If taskbar is showing, its
      * inset is not included here.
      */
@@ -292,16 +303,19 @@
         int leftPadding = mInsets.left + mExpandedViewPadding;
         int rightPadding = mInsets.right + mExpandedViewPadding;
         final boolean isLargeOrOverflow = mIsLargeScreen || isOverflow;
+        final float expandedViewWidth = isOverflow
+                ? mOverflowWidth
+                : mExpandedViewLargeScreenWidth;
         if (showBubblesVertically()) {
             if (!onLeft) {
                 rightPadding += mBubbleSize - mPointerHeight;
                 leftPadding += isLargeOrOverflow
-                        ? (mPositionRect.width() - rightPadding - mExpandedViewLargeScreenWidth)
+                        ? (mPositionRect.width() - rightPadding - expandedViewWidth)
                         : 0;
             } else {
                 leftPadding += mBubbleSize - mPointerHeight;
                 rightPadding += isLargeOrOverflow
-                        ? (mPositionRect.width() - leftPadding - mExpandedViewLargeScreenWidth)
+                        ? (mPositionRect.width() - leftPadding - expandedViewWidth)
                         : 0;
             }
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 8f2df4a..3d2505e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -110,9 +110,6 @@
 
     private static final int FADE_IN_DURATION = 320;
 
-    /** Percent to darken the bubbles when they're in the dismiss target. */
-    private static final float DARKEN_PERCENT = 0.3f;
-
     /** How long to wait, in milliseconds, before hiding the flyout. */
     @VisibleForTesting
     static final int FLYOUT_HIDE_AFTER = 5000;
@@ -559,7 +556,7 @@
 
             if (mBubbleData.isExpanded()) {
                 if (mManageEduView != null) {
-                    mManageEduView.hide(false /* show */);
+                    mManageEduView.hide();
                 }
 
                 // If we're expanded, tell the animation controller to prepare to drag this bubble,
@@ -797,8 +794,6 @@
         mBubbleContainer.setClipChildren(false);
         addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
 
-        updateUserEdu();
-
         mExpandedViewContainer = new FrameLayout(context);
         mExpandedViewContainer.setElevation(elevation);
         mExpandedViewContainer.setClipChildren(false);
@@ -932,8 +927,10 @@
         setOnClickListener(view -> {
             if (mShowingManage) {
                 showManageMenu(false /* show */);
+            } else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+                mManageEduView.hide();
             } else if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
-                mStackEduView.hide(false);
+                mStackEduView.hide(false /* isExpanding */);
             } else if (mBubbleData.isExpanded()) {
                 mBubbleData.setExpanded(false);
             }
@@ -1132,10 +1129,10 @@
             return;
         }
         if (mManageEduView == null) {
-            mManageEduView = new ManageEducationView(mContext);
+            mManageEduView = new ManageEducationView(mContext, mPositioner);
             addView(mManageEduView);
         }
-        mManageEduView.show(mExpandedBubble.getExpandedView(), mTempRect);
+        mManageEduView.show(mExpandedBubble.getExpandedView());
     }
 
     /**
@@ -1163,21 +1160,27 @@
             return false;
         }
         if (mStackEduView == null) {
-            mStackEduView = new StackEducationView(mContext);
+            mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController);
             addView(mStackEduView);
         }
         mBubbleContainer.bringToFront();
         return mStackEduView.show(mPositioner.getDefaultStartPosition());
     }
 
+    // Recreates & shows the education views. Call when a theme/config change happens.
     private void updateUserEdu() {
-        maybeShowStackEdu();
-        if (mManageEduView != null) {
-            mManageEduView.invalidate();
+        if (mStackEduView != null && mStackEduView.getVisibility() == VISIBLE) {
+            removeView(mStackEduView);
+            mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController);
+            addView(mStackEduView);
+            mBubbleContainer.bringToFront(); // Stack appears on top of the stack education
+            mStackEduView.show(mPositioner.getDefaultStartPosition());
         }
-        maybeShowManageEdu();
-        if (mStackEduView != null) {
-            mStackEduView.invalidate();
+        if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+            removeView(mManageEduView);
+            mManageEduView = new ManageEducationView(mContext, mPositioner);
+            addView(mManageEduView);
+            mManageEduView.show(mExpandedBubble.getExpandedView());
         }
     }
 
@@ -1274,6 +1277,7 @@
         setUpManageMenu();
         setUpFlyout();
         setUpDismissView();
+        updateUserEdu();
         mBubbleSize = mPositioner.getBubbleSize();
         for (Bubble b : mBubbleData.getBubbles()) {
             if (b.getIconView() == null) {
@@ -1730,6 +1734,21 @@
         notifyExpansionChanged(mExpandedBubble, mIsExpanded);
     }
 
+    /**
+     * Called when back press occurs while bubbles are expanded.
+     */
+    public void onBackPressed() {
+        if (mIsExpanded) {
+            if (mShowingManage) {
+                showManageMenu(false);
+            } else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+                mManageEduView.hide();
+            } else {
+                setExpanded(false);
+            }
+        }
+    }
+
     void setBubbleVisibility(Bubble b, boolean visible) {
         if (b.getIconView() != null) {
             b.getIconView().setVisibility(visible ? VISIBLE : GONE);
@@ -1955,6 +1974,9 @@
     private void animateCollapse() {
         cancelDelayedExpandCollapseSwitchAnimations();
 
+        if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
+            mManageEduView.hide();
+        }
         // Hide the menu if it's visible.
         showManageMenu(false);
 
@@ -2032,7 +2054,7 @@
                     final BubbleViewProvider previouslySelected = mExpandedBubble;
                     beforeExpandedViewAnimation();
                     if (mManageEduView != null) {
-                        mManageEduView.hide(false /* fromExpansion */);
+                        mManageEduView.hide();
                     }
 
                     if (DEBUG_BUBBLE_STACK_VIEW) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
index 4cc6702..eb4737a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
@@ -18,12 +18,13 @@
 import android.content.Context
 import android.graphics.Color
 import android.graphics.Rect
+import android.graphics.drawable.ColorDrawable
 import android.view.LayoutInflater
 import android.view.View
+import android.view.ViewGroup
 import android.widget.Button
 import android.widget.LinearLayout
-import android.widget.TextView
-import com.android.internal.util.ContrastColorUtil
+import com.android.internal.R.color.system_neutral1_900
 import com.android.wm.shell.R
 import com.android.wm.shell.animation.Interpolators
 
@@ -31,21 +32,22 @@
  * User education view to highlight the manage button that allows a user to configure the settings
  * for the bubble. Shown only the first time a user expands a bubble.
  */
-class ManageEducationView constructor(context: Context) : LinearLayout(context) {
+class ManageEducationView constructor(context: Context, positioner: BubblePositioner)
+    : LinearLayout(context) {
 
-    private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleManageEducationView"
+    private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "ManageEducationView"
         else BubbleDebugConfig.TAG_BUBBLES
 
     private val ANIMATE_DURATION: Long = 200
-    private val ANIMATE_DURATION_SHORT: Long = 40
 
-    private val manageView by lazy { findViewById<View>(R.id.manage_education_view) }
-    private val manageButton by lazy { findViewById<Button>(R.id.manage) }
+    private val positioner: BubblePositioner = positioner
+    private val manageView by lazy { findViewById<ViewGroup>(R.id.manage_education_view) }
+    private val manageButton by lazy { findViewById<Button>(R.id.manage_button) }
     private val gotItButton by lazy { findViewById<Button>(R.id.got_it) }
-    private val titleTextView by lazy { findViewById<TextView>(R.id.user_education_title) }
-    private val descTextView by lazy { findViewById<TextView>(R.id.user_education_description) }
 
     private var isHiding = false
+    private var realManageButtonRect = Rect()
+    private var bubbleExpandedView: BubbleExpandedView? = null
 
     init {
         LayoutInflater.from(context).inflate(R.layout.bubbles_manage_button_education, this)
@@ -66,18 +68,17 @@
     override fun onFinishInflate() {
         super.onFinishInflate()
         layoutDirection = resources.configuration.layoutDirection
-        setTextColor()
     }
 
-    private fun setTextColor() {
-        val typedArray = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent,
-            android.R.attr.textColorPrimaryInverse))
-        val bgColor = typedArray.getColor(0 /* index */, Color.BLACK)
-        var textColor = typedArray.getColor(1 /* index */, Color.WHITE)
+    private fun setButtonColor() {
+        val typedArray = mContext.obtainStyledAttributes(intArrayOf(
+                com.android.internal.R.attr.colorAccentPrimary))
+        val buttonColor = typedArray.getColor(0 /* index */, Color.TRANSPARENT)
         typedArray.recycle()
-        textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true)
-        titleTextView.setTextColor(textColor)
-        descTextView.setTextColor(textColor)
+
+        manageButton.setTextColor(mContext.getColor(system_neutral1_900))
+        manageButton.setBackgroundDrawable(ColorDrawable(buttonColor))
+        gotItButton.setBackgroundDrawable(ColorDrawable(buttonColor))
     }
 
     private fun setDrawableDirection() {
@@ -91,30 +92,39 @@
      * If necessary, toggles the user education view for the manage button. This is shown when the
      * bubble stack is expanded for the first time.
      *
-     * @param show whether the user education view should show or not.
+     * @param expandedView the expandedView the user education is shown on top of.
      */
-    fun show(expandedView: BubbleExpandedView, rect: Rect) {
+    fun show(expandedView: BubbleExpandedView) {
+        setButtonColor()
         if (visibility == VISIBLE) return
 
+        bubbleExpandedView = expandedView
+        expandedView.taskView?.setObscuredTouchRect(Rect(positioner.screenRect))
+
+        layoutParams.width = if (positioner.isLargeScreen)
+            context.resources.getDimensionPixelSize(
+                    R.dimen.bubbles_user_education_width_large_screen)
+        else ViewGroup.LayoutParams.MATCH_PARENT
+
         alpha = 0f
         visibility = View.VISIBLE
+        expandedView.getManageButtonBoundsOnScreen(realManageButtonRect)
+        manageView.setPadding(realManageButtonRect.left - expandedView.manageButtonMargin,
+                manageView.paddingTop, manageView.paddingRight, manageView.paddingBottom)
         post {
-            expandedView.getManageButtonBoundsOnScreen(rect)
-
             manageButton
                 .setOnClickListener {
-                    expandedView.findViewById<View>(R.id.settings_button).performClick()
-                    hide(true /* isStackExpanding */)
+                    hide()
+                    expandedView.findViewById<View>(R.id.manage_button).performClick()
                 }
-            gotItButton.setOnClickListener { hide(true /* isStackExpanding */) }
-            setOnClickListener { hide(true /* isStackExpanding */) }
+            gotItButton.setOnClickListener { hide() }
+            setOnClickListener { hide() }
 
-            with(manageView) {
-                translationX = 0f
-                val inset = resources.getDimensionPixelSize(
-                    R.dimen.bubbles_manage_education_top_inset)
-                translationY = (rect.top - manageView.height + inset).toFloat()
-            }
+            val offsetViewBounds = Rect()
+            manageButton.getDrawingRect(offsetViewBounds)
+            manageView.offsetDescendantRectToMyCoords(manageButton, offsetViewBounds)
+            translationX = 0f
+            translationY = (realManageButtonRect.top - offsetViewBounds.top).toFloat()
             bringToFront()
             animate()
                 .setDuration(ANIMATE_DURATION)
@@ -124,13 +134,14 @@
         setShouldShow(false)
     }
 
-    fun hide(isStackExpanding: Boolean) {
+    fun hide() {
+        bubbleExpandedView?.taskView?.setObscuredTouchRect(null)
         if (visibility != VISIBLE || isHiding) return
 
         animate()
             .withStartAction { isHiding = true }
             .alpha(0f)
-            .setDuration(if (isStackExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+            .setDuration(ANIMATE_DURATION)
             .withEndAction {
                 isHiding = false
                 visibility = GONE
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
index 0a2cfc4..f6a90b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
@@ -18,8 +18,11 @@
 import android.content.Context
 import android.graphics.Color
 import android.graphics.PointF
+import android.view.KeyEvent
 import android.view.LayoutInflater
 import android.view.View
+import android.view.View.OnKeyListener
+import android.view.ViewGroup
 import android.widget.LinearLayout
 import android.widget.TextView
 import com.android.internal.util.ContrastColorUtil
@@ -30,7 +33,12 @@
  * User education view to highlight the collapsed stack of bubbles.
  * Shown only the first time a user taps the stack.
  */
-class StackEducationView constructor(context: Context) : LinearLayout(context) {
+class StackEducationView constructor(
+    context: Context,
+    positioner: BubblePositioner,
+    controller: BubbleController
+)
+    : LinearLayout(context) {
 
     private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView"
         else BubbleDebugConfig.TAG_BUBBLES
@@ -38,6 +46,9 @@
     private val ANIMATE_DURATION: Long = 200
     private val ANIMATE_DURATION_SHORT: Long = 40
 
+    private val positioner: BubblePositioner = positioner
+    private val controller: BubbleController = controller
+
     private val view by lazy { findViewById<View>(R.id.stack_education_layout) }
     private val titleTextView by lazy { findViewById<TextView>(R.id.stack_education_title) }
     private val descTextView by lazy { findViewById<TextView>(R.id.stack_education_description) }
@@ -67,6 +78,28 @@
         setTextColor()
     }
 
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        setFocusableInTouchMode(true)
+        setOnKeyListener(object : OnKeyListener {
+            override fun onKey(v: View?, keyCode: Int, event: KeyEvent): Boolean {
+                // if the event is a key down event on the enter button
+                if (event.action == KeyEvent.ACTION_UP &&
+                        keyCode == KeyEvent.KEYCODE_BACK && !isHiding) {
+                    hide(false)
+                    return true
+                }
+                return false
+            }
+        })
+    }
+
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        setOnKeyListener(null)
+        controller.updateWindowFlagsForBackpress(false /* interceptBack */)
+    }
+
     private fun setTextColor() {
         val ta = mContext.obtainStyledAttributes(intArrayOf(android.R.attr.colorAccent,
             android.R.attr.textColorPrimaryInverse))
@@ -94,13 +127,25 @@
     fun show(stackPosition: PointF): Boolean {
         if (visibility == VISIBLE) return false
 
+        controller.updateWindowFlagsForBackpress(true /* interceptBack */)
+        layoutParams.width = if (positioner.isLargeScreen)
+            context.resources.getDimensionPixelSize(
+                    R.dimen.bubbles_user_education_width_large_screen)
+        else ViewGroup.LayoutParams.MATCH_PARENT
+
         setAlpha(0f)
         setVisibility(View.VISIBLE)
         post {
+            requestFocus()
             with(view) {
-                val bubbleSize = context.resources.getDimensionPixelSize(
-                    R.dimen.bubble_size)
-                translationY = stackPosition.y + bubbleSize / 2 - getHeight() / 2
+                if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR) {
+                    setPadding(positioner.bubbleSize + paddingRight, paddingTop, paddingRight,
+                            paddingBottom)
+                } else {
+                    setPadding(paddingLeft, paddingTop, positioner.bubbleSize + paddingLeft,
+                            paddingBottom)
+                }
+                translationY = stackPosition.y + positioner.bubbleSize / 2 - getHeight() / 2
             }
             animate()
                 .setDuration(ANIMATE_DURATION)
@@ -114,15 +159,16 @@
     /**
      * If necessary, hides the stack education view.
      *
-     * @param fromExpansion if true this indicates the hide is happening due to the bubble being
+     * @param isExpanding if true this indicates the hide is happening due to the bubble being
      *                      expanded, false if due to a touch outside of the bubble stack.
      */
-    fun hide(fromExpansion: Boolean) {
+    fun hide(isExpanding: Boolean) {
         if (visibility != VISIBLE || isHiding) return
 
+        controller.updateWindowFlagsForBackpress(false /* interceptBack */)
         animate()
             .alpha(0f)
-            .setDuration(if (fromExpansion) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
+            .setDuration(if (isExpanding) ANIMATE_DURATION_SHORT else ANIMATE_DURATION)
             .withEndAction { visibility = GONE }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index efe07fb..007ddbf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -64,9 +64,6 @@
     /** Stiffness for the expand/collapse path-following animation. */
     private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 1000;
 
-    /** What percentage of the screen to use when centering the bubbles in landscape. */
-    private static final float CENTER_BUBBLES_LANDSCAPE_PERCENT = 0.66f;
-
     /**
      * Velocity required to dismiss an individual bubble without dragging it into the dismiss
      * target.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
index 3a7b534..ffda1f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
@@ -17,6 +17,7 @@
 package com.android.wm.shell.common;
 
 import android.os.RemoteException;
+import android.util.Slog;
 import android.view.IDisplayWindowRotationCallback;
 import android.view.IDisplayWindowRotationController;
 import android.view.IWindowManager;
@@ -27,6 +28,7 @@
 import com.android.wm.shell.common.annotations.ShellMainThread;
 
 import java.util.ArrayList;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * This module deals with display rotations coming from WM. When WM starts a rotation: after it has
@@ -35,14 +37,14 @@
  * rotation.
  */
 public class DisplayChangeController {
+    private static final String TAG = DisplayChangeController.class.getSimpleName();
 
     private final ShellExecutor mMainExecutor;
     private final IWindowManager mWmService;
     private final IDisplayWindowRotationController mControllerImpl;
 
-    private final ArrayList<OnDisplayChangingListener> mRotationListener =
-            new ArrayList<>();
-    private final ArrayList<OnDisplayChangingListener> mTmpListeners = new ArrayList<>();
+    private final CopyOnWriteArrayList<OnDisplayChangingListener> mRotationListener =
+            new CopyOnWriteArrayList<>();
 
     public DisplayChangeController(IWindowManager wmService, ShellExecutor mainExecutor) {
         mMainExecutor = mainExecutor;
@@ -59,34 +61,26 @@
      * Adds a display rotation controller.
      */
     public void addRotationListener(OnDisplayChangingListener listener) {
-        synchronized (mRotationListener) {
-            mRotationListener.add(listener);
-        }
+        mRotationListener.add(listener);
     }
 
     /**
      * Removes a display rotation controller.
      */
     public void removeRotationListener(OnDisplayChangingListener listener) {
-        synchronized (mRotationListener) {
-            mRotationListener.remove(listener);
-        }
+        mRotationListener.remove(listener);
     }
 
     private void onRotateDisplay(int displayId, final int fromRotation, final int toRotation,
             IDisplayWindowRotationCallback callback) {
         WindowContainerTransaction t = new WindowContainerTransaction();
-        synchronized (mRotationListener) {
-            mTmpListeners.clear();
-            // Make a local copy in case the handlers add/remove themselves.
-            mTmpListeners.addAll(mRotationListener);
-        }
-        for (OnDisplayChangingListener c : mTmpListeners) {
+        for (OnDisplayChangingListener c : mRotationListener) {
             c.onRotateDisplay(displayId, fromRotation, toRotation, t);
         }
         try {
             callback.continueRotateDisplay(toRotation, t);
         } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to continue rotation", e);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index ba9ba5e..9a3bdab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -26,6 +26,7 @@
 import android.view.Display;
 import android.view.IDisplayWindowListener;
 import android.view.IWindowManager;
+import android.view.InsetsState;
 
 import androidx.annotation.BinderThread;
 
@@ -52,14 +53,6 @@
     private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
     private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>();
 
-    /**
-     * Gets a display by id from DisplayManager.
-     */
-    public Display getDisplay(int displayId) {
-        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
-        return displayManager.getDisplay(displayId);
-    }
-
     public DisplayController(Context context, IWindowManager wmService,
             ShellExecutor mainExecutor) {
         mMainExecutor = mainExecutor;
@@ -67,14 +60,28 @@
         mWmService = wmService;
         mChangeController = new DisplayChangeController(mWmService, mainExecutor);
         mDisplayContainerListener = new DisplayWindowListenerImpl();
+    }
+
+    /**
+     * Initializes the window listener.
+     */
+    public void initialize() {
         try {
             mWmService.registerDisplayWindowListener(mDisplayContainerListener);
         } catch (RemoteException e) {
-            throw new RuntimeException("Unable to register hierarchy listener");
+            throw new RuntimeException("Unable to register display controller");
         }
     }
 
     /**
+     * Gets a display by id from DisplayManager.
+     */
+    public Display getDisplay(int displayId) {
+        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+        return displayManager.getDisplay(displayId);
+    }
+
+    /**
      * Gets the DisplayLayout associated with a display.
      */
     public @Nullable DisplayLayout getDisplayLayout(int displayId) {
@@ -91,6 +98,16 @@
     }
 
     /**
+     * Updates the insets for a given display.
+     */
+    public void updateDisplayInsets(int displayId, InsetsState state) {
+        final DisplayRecord r = mDisplays.get(displayId);
+        if (r != null) {
+            r.setInsets(state);
+        }
+    }
+
+    /**
      * Add a display window-container listener. It will get notified whenever a display's
      * configuration changes or when displays are added/removed from the WM hierarchy.
      */
@@ -134,17 +151,18 @@
             if (mDisplays.get(displayId) != null) {
                 return;
             }
-            Display display = getDisplay(displayId);
+            final Display display = getDisplay(displayId);
             if (display == null) {
                 // It's likely that the display is private to some app and thus not
                 // accessible by system-ui.
                 return;
             }
-            DisplayRecord record = new DisplayRecord();
-            record.mDisplayId = displayId;
-            record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
+
+            final Context context = (displayId == Display.DEFAULT_DISPLAY)
+                    ? mContext
                     : mContext.createDisplayContext(display);
-            record.mDisplayLayout = new DisplayLayout(record.mContext, display);
+            final DisplayRecord record = new DisplayRecord(displayId);
+            record.setDisplayLayout(context, new DisplayLayout(context, display));
             mDisplays.put(displayId, record);
             for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
                 mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
@@ -154,24 +172,23 @@
 
     private void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
         synchronized (mDisplays) {
-            DisplayRecord dr = mDisplays.get(displayId);
+            final DisplayRecord dr = mDisplays.get(displayId);
             if (dr == null) {
                 Slog.w(TAG, "Skipping Display Configuration change on non-added"
                         + " display.");
                 return;
             }
-            Display display = getDisplay(displayId);
+            final Display display = getDisplay(displayId);
             if (display == null) {
                 Slog.w(TAG, "Skipping Display Configuration change on invalid"
                         + " display. It may have been removed.");
                 return;
             }
-            Context perDisplayContext = mContext;
-            if (displayId != Display.DEFAULT_DISPLAY) {
-                perDisplayContext = mContext.createDisplayContext(display);
-            }
-            dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
-            dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
+            final Context perDisplayContext = (displayId == Display.DEFAULT_DISPLAY)
+                    ? mContext
+                    : mContext.createDisplayContext(display);
+            final Context context = perDisplayContext.createConfigurationContext(newConfig);
+            dr.setDisplayLayout(context, new DisplayLayout(context, display));
             for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
                 mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
                         displayId, newConfig);
@@ -219,9 +236,25 @@
     }
 
     private static class DisplayRecord {
-        int mDisplayId;
-        Context mContext;
-        DisplayLayout mDisplayLayout;
+        private int mDisplayId;
+        private Context mContext;
+        private DisplayLayout mDisplayLayout;
+        private InsetsState mInsetsState = new InsetsState();
+
+        private DisplayRecord(int displayId) {
+            mDisplayId = displayId;
+        }
+
+        private void setDisplayLayout(Context context, DisplayLayout displayLayout) {
+            mContext = context;
+            mDisplayLayout = displayLayout;
+            mDisplayLayout.setInsets(mContext.getResources(), mInsetsState);
+        }
+
+        private void setInsets(InsetsState state) {
+            mInsetsState = state;
+            mDisplayLayout.setInsets(mContext.getResources(), state);
+        }
     }
 
     @BinderThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index ba59e07..a7052bc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -69,14 +69,17 @@
     protected final Executor mMainExecutor;
     private final TransactionPool mTransactionPool;
     private final DisplayController mDisplayController;
+    private final DisplayInsetsController mDisplayInsetsController;
     private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
     private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
 
 
     public DisplayImeController(IWindowManager wmService, DisplayController displayController,
+            DisplayInsetsController displayInsetsController,
             Executor mainExecutor, TransactionPool transactionPool) {
         mWmService = wmService;
         mDisplayController = displayController;
+        mDisplayInsetsController = displayInsetsController;
         mMainExecutor = mainExecutor;
         mTransactionPool = transactionPool;
     }
@@ -110,11 +113,11 @@
 
     @Override
     public void onDisplayRemoved(int displayId) {
-        try {
-            mWmService.setDisplayWindowInsetsController(displayId, null);
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
+        PerDisplay pd = mImePerDisplay.get(displayId);
+        if (pd == null) {
+            return;
         }
+        pd.unregister();
         mImePerDisplay.remove(displayId);
     }
 
@@ -196,12 +199,10 @@
     }
 
     /** An implementation of {@link IDisplayWindowInsetsController} for a given display id. */
-    public class PerDisplay {
+    public class PerDisplay implements DisplayInsetsController.OnInsetsChangedListener {
         final int mDisplayId;
         final InsetsState mInsetsState = new InsetsState();
         final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
-        protected final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
-                new DisplayWindowInsetsControllerImpl();
         InsetsSourceControl mImeSourceControl = null;
         int mAnimationDirection = DIRECTION_NONE;
         ValueAnimator mAnimation = null;
@@ -216,14 +217,15 @@
         }
 
         public void register() {
-            try {
-                mWmService.setDisplayWindowInsetsController(mDisplayId, mInsetsControllerImpl);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Unable to set insets controller on display " + mDisplayId);
-            }
+            mDisplayInsetsController.addInsetsChangedListener(mDisplayId, this);
         }
 
-        protected void insetsChanged(InsetsState insetsState) {
+        public void unregister() {
+            mDisplayInsetsController.removeInsetsChangedListener(mDisplayId, this);
+        }
+
+        @Override
+        public void insetsChanged(InsetsState insetsState) {
             if (mInsetsState.equals(insetsState)) {
                 return;
             }
@@ -241,8 +243,9 @@
             }
         }
 
+        @Override
         @VisibleForTesting
-        protected void insetsControlChanged(InsetsState insetsState,
+        public void insetsControlChanged(InsetsState insetsState,
                 InsetsSourceControl[] activeControls) {
             insetsChanged(insetsState);
             InsetsSourceControl imeSourceControl = null;
@@ -303,7 +306,8 @@
             }
         }
 
-        protected void showInsets(int types, boolean fromIme) {
+        @Override
+        public void showInsets(int types, boolean fromIme) {
             if ((types & WindowInsets.Type.ime()) == 0) {
                 return;
             }
@@ -311,8 +315,8 @@
             startAnimation(true /* show */, false /* forceRestart */);
         }
 
-
-        protected void hideInsets(int types, boolean fromIme) {
+        @Override
+        public void hideInsets(int types, boolean fromIme) {
             if ((types & WindowInsets.Type.ime()) == 0) {
                 return;
             }
@@ -320,6 +324,7 @@
             startAnimation(false /* show */, false /* forceRestart */);
         }
 
+        @Override
         public void topFocusedWindowChanged(String packageName) {
             // Do nothing
         }
@@ -493,47 +498,6 @@
                 dispatchVisibilityChanged(mDisplayId, isShowing);
             }
         }
-
-        @VisibleForTesting
-        @BinderThread
-        public class DisplayWindowInsetsControllerImpl
-                extends IDisplayWindowInsetsController.Stub {
-            @Override
-            public void topFocusedWindowChanged(String packageName) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.topFocusedWindowChanged(packageName);
-                });
-            }
-
-            @Override
-            public void insetsChanged(InsetsState insetsState) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.insetsChanged(insetsState);
-                });
-            }
-
-            @Override
-            public void insetsControlChanged(InsetsState insetsState,
-                    InsetsSourceControl[] activeControls) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.insetsControlChanged(insetsState, activeControls);
-                });
-            }
-
-            @Override
-            public void showInsets(int types, boolean fromIme) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.showInsets(types, fromIme);
-                });
-            }
-
-            @Override
-            public void hideInsets(int types, boolean fromIme) throws RemoteException {
-                mMainExecutor.execute(() -> {
-                    PerDisplay.this.hideInsets(types, fromIme);
-                });
-            }
-        }
     }
 
     void removeImeSurface() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
new file mode 100644
index 0000000..5f3de7e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
@@ -0,0 +1,265 @@
+/*
+ * 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.wm.shell.common;
+
+import android.os.RemoteException;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.IDisplayWindowInsetsController;
+import android.view.IWindowManager;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+
+import androidx.annotation.BinderThread;
+
+import com.android.wm.shell.common.annotations.ShellMainThread;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Manages insets from the core.
+ */
+public class DisplayInsetsController implements DisplayController.OnDisplaysChangedListener {
+    private static final String TAG = "DisplayInsetsController";
+
+    private final IWindowManager mWmService;
+    private final ShellExecutor mMainExecutor;
+    private final DisplayController mDisplayController;
+    private final SparseArray<PerDisplay> mInsetsPerDisplay = new SparseArray<>();
+    private final SparseArray<CopyOnWriteArrayList<OnInsetsChangedListener>> mListeners =
+            new SparseArray<>();
+
+    public DisplayInsetsController(IWindowManager wmService, DisplayController displayController,
+            ShellExecutor mainExecutor) {
+        mWmService = wmService;
+        mDisplayController = displayController;
+        mMainExecutor = mainExecutor;
+    }
+
+    /**
+     * Starts listening for insets for each display.
+     **/
+    public void initialize() {
+        mDisplayController.addDisplayWindowListener(this);
+    }
+
+    /**
+     * Adds a callback to listen for insets changes for a particular display.  Note that the
+     * listener will not be updated with the existing state of the insets on that display.
+     */
+    public void addInsetsChangedListener(int displayId, OnInsetsChangedListener listener) {
+        CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(displayId);
+        if (listeners == null) {
+            listeners = new CopyOnWriteArrayList<>();
+            mListeners.put(displayId, listeners);
+        }
+        if (!listeners.contains(listener)) {
+            listeners.add(listener);
+        }
+    }
+
+    /**
+     * Removes a callback listening for insets changes from a particular display.
+     */
+    public void removeInsetsChangedListener(int displayId, OnInsetsChangedListener listener) {
+        CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(displayId);
+        if (listeners == null) {
+            return;
+        }
+        listeners.remove(listener);
+    }
+
+    @Override
+    public void onDisplayAdded(int displayId) {
+        PerDisplay pd = new PerDisplay(displayId);
+        pd.register();
+        mInsetsPerDisplay.put(displayId, pd);
+    }
+
+    @Override
+    public void onDisplayRemoved(int displayId) {
+        PerDisplay pd = mInsetsPerDisplay.get(displayId);
+        if (pd == null) {
+            return;
+        }
+        pd.unregister();
+        mInsetsPerDisplay.remove(displayId);
+    }
+
+    /**
+     * An implementation of {@link IDisplayWindowInsetsController} for a given display id.
+     **/
+    public class PerDisplay {
+        private final int mDisplayId;
+        private final DisplayWindowInsetsControllerImpl mInsetsControllerImpl =
+                new DisplayWindowInsetsControllerImpl();
+
+        public PerDisplay(int displayId) {
+            mDisplayId = displayId;
+        }
+
+        public void register() {
+            try {
+                mWmService.setDisplayWindowInsetsController(mDisplayId, mInsetsControllerImpl);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Unable to set insets controller on display " + mDisplayId);
+            }
+        }
+
+        public void unregister() {
+            try {
+                mWmService.setDisplayWindowInsetsController(mDisplayId, null);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Unable to remove insets controller on display " + mDisplayId);
+            }
+        }
+
+        private void insetsChanged(InsetsState insetsState) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            mDisplayController.updateDisplayInsets(mDisplayId, insetsState);
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.insetsChanged(insetsState);
+            }
+        }
+
+        private void insetsControlChanged(InsetsState insetsState,
+                InsetsSourceControl[] activeControls) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.insetsControlChanged(insetsState, activeControls);
+            }
+        }
+
+        private void showInsets(int types, boolean fromIme) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.showInsets(types, fromIme);
+            }
+        }
+
+        private void hideInsets(int types, boolean fromIme) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.hideInsets(types, fromIme);
+            }
+        }
+
+        private void topFocusedWindowChanged(String packageName) {
+            CopyOnWriteArrayList<OnInsetsChangedListener> listeners = mListeners.get(mDisplayId);
+            if (listeners == null) {
+                return;
+            }
+            for (OnInsetsChangedListener listener : listeners) {
+                listener.topFocusedWindowChanged(packageName);
+            }
+        }
+
+        @BinderThread
+        private class DisplayWindowInsetsControllerImpl
+                extends IDisplayWindowInsetsController.Stub {
+            @Override
+            public void topFocusedWindowChanged(String packageName) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.topFocusedWindowChanged(packageName);
+                });
+            }
+
+            @Override
+            public void insetsChanged(InsetsState insetsState) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.insetsChanged(insetsState);
+                });
+            }
+
+            @Override
+            public void insetsControlChanged(InsetsState insetsState,
+                    InsetsSourceControl[] activeControls) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.insetsControlChanged(insetsState, activeControls);
+                });
+            }
+
+            @Override
+            public void showInsets(int types, boolean fromIme) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.showInsets(types, fromIme);
+                });
+            }
+
+            @Override
+            public void hideInsets(int types, boolean fromIme) throws RemoteException {
+                mMainExecutor.execute(() -> {
+                    PerDisplay.this.hideInsets(types, fromIme);
+                });
+            }
+        }
+    }
+
+    /**
+     * Gets notified whenever the insets change.
+     *
+     * @see IDisplayWindowInsetsController
+     */
+    @ShellMainThread
+    public interface OnInsetsChangedListener {
+        /**
+         * Called when top focused window changes to determine whether or not to take over insets
+         * control. Won't be called if config_remoteInsetsControllerControlsSystemBars is false.
+         * @param packageName: Passes the top package name
+         */
+        void topFocusedWindowChanged(String packageName);
+
+        /**
+         * Called when the window insets configuration has changed.
+         */
+        void insetsChanged(InsetsState insetsState);
+
+        /**
+         * Called when this window retrieved control over a specified set of insets sources.
+         */
+        void insetsControlChanged(InsetsState insetsState,
+                InsetsSourceControl[] activeControls);
+
+        /**
+         * Called when a set of insets source window should be shown by policy.
+         *
+         * @param types internal insets types (WindowInsets.Type.InsetsType) to show
+         * @param fromIme true if this request originated from IME (InputMethodService).
+         */
+        void showInsets(int types, boolean fromIme);
+
+        /**
+         * Called when a set of insets source window should be hidden by policy.
+         *
+         * @param types internal insets types (WindowInsets.Type.InsetsType) to hide
+         * @param fromIme true if this request originated from IME (InputMethodService).
+         */
+        void hideInsets(int types, boolean fromIme);
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index b90283f..962aca1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -25,6 +25,7 @@
 import static android.util.RotationUtils.rotateBounds;
 import static android.util.RotationUtils.rotateInsets;
 import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
@@ -44,7 +45,10 @@
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
+import android.view.InsetsSource;
+import android.view.InsetsState;
 import android.view.Surface;
+import android.view.WindowInsets;
 
 import com.android.internal.R;
 
@@ -85,6 +89,7 @@
     private boolean mAllowSeamlessRotationDespiteNavBarMoving = false;
     private boolean mNavigationBarCanMove = false;
     private boolean mReverseDefaultRotation = false;
+    private InsetsState mInsetsState = new InsetsState();
 
     @Override
     public boolean equals(Object o) {
@@ -105,7 +110,8 @@
                         == other.mAllowSeamlessRotationDespiteNavBarMoving
                 && mNavigationBarCanMove == other.mNavigationBarCanMove
                 && mReverseDefaultRotation == other.mReverseDefaultRotation
-                && mNavBarFrameHeight == other.mNavBarFrameHeight;
+                && mNavBarFrameHeight == other.mNavBarFrameHeight
+                && Objects.equals(mInsetsState, other.mInsetsState);
     }
 
     @Override
@@ -113,7 +119,7 @@
         return Objects.hash(mUiMode, mWidth, mHeight, mCutout, mRotation, mDensityDpi,
                 mNonDecorInsets, mStableInsets, mHasNavigationBar, mHasStatusBar,
                 mNavBarFrameHeight, mAllowSeamlessRotationDespiteNavBarMoving,
-                mNavigationBarCanMove, mReverseDefaultRotation);
+                mNavigationBarCanMove, mReverseDefaultRotation, mInsetsState);
     }
 
     /**
@@ -164,6 +170,7 @@
         mNavBarFrameHeight = dl.mNavBarFrameHeight;
         mNonDecorInsets.set(dl.mNonDecorInsets);
         mStableInsets.set(dl.mStableInsets);
+        mInsetsState.set(dl.mInsetsState, true /* copySources */);
     }
 
     private void init(DisplayInfo info, Resources res, boolean hasNavigationBar,
@@ -183,9 +190,17 @@
         recalcInsets(res);
     }
 
+    /**
+     * Updates the current insets.
+     */
+    public void setInsets(Resources res, InsetsState state) {
+        mInsetsState = state;
+        recalcInsets(res);
+    }
+
     private void recalcInsets(Resources res) {
-        computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mUiMode, mNonDecorInsets,
-                mHasNavigationBar);
+        computeNonDecorInsets(res, mRotation, mWidth, mHeight, mCutout, mInsetsState, mUiMode,
+                mNonDecorInsets, mHasNavigationBar);
         mStableInsets.set(mNonDecorInsets);
         if (mHasStatusBar) {
             convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar);
@@ -259,7 +274,7 @@
         return mWidth > mHeight;
     }
 
-    /** Get the navbar frame height (used by ime). */
+    /** Get the navbar frame (or window) height (used by ime). */
     public int navBarFrameHeight() {
         return mNavBarFrameHeight;
     }
@@ -328,21 +343,29 @@
      * @param outInsets the insets to return
      */
     static void computeNonDecorInsets(Resources res, int displayRotation, int displayWidth,
-            int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
-            boolean hasNavigationBar) {
+            int displayHeight, DisplayCutout displayCutout, InsetsState insetsState, int uiMode,
+            Rect outInsets, boolean hasNavigationBar) {
         outInsets.setEmpty();
 
         // Only navigation bar
         if (hasNavigationBar) {
+            final InsetsSource extraNavBar = insetsState.getSource(ITYPE_EXTRA_NAVIGATION_BAR);
+            final boolean hasExtraNav = extraNavBar != null && extraNavBar.isVisible();
             int position = navigationBarPosition(res, displayWidth, displayHeight, displayRotation);
             int navBarSize =
                     getNavigationBarSize(res, position, displayWidth > displayHeight, uiMode);
             if (position == NAV_BAR_BOTTOM) {
-                outInsets.bottom = navBarSize;
+                outInsets.bottom = hasExtraNav
+                        ? Math.max(navBarSize, extraNavBar.getFrame().height())
+                        : navBarSize;
             } else if (position == NAV_BAR_RIGHT) {
-                outInsets.right = navBarSize;
+                outInsets.right = hasExtraNav
+                        ? Math.max(navBarSize, extraNavBar.getFrame().width())
+                        : navBarSize;
             } else if (position == NAV_BAR_LEFT) {
-                outInsets.left = navBarSize;
+                outInsets.left = hasExtraNav
+                        ? Math.max(navBarSize, extraNavBar.getFrame().width())
+                        : navBarSize;
             }
         }
 
@@ -364,13 +387,13 @@
      * @param outInsets the insets to return
      */
     static void computeStableInsets(Resources res, int displayRotation, int displayWidth,
-            int displayHeight, DisplayCutout displayCutout, int uiMode, Rect outInsets,
-            boolean hasNavigationBar, boolean hasStatusBar) {
+            int displayHeight, DisplayCutout displayCutout, InsetsState insetsState, int uiMode,
+            Rect outInsets, boolean hasNavigationBar, boolean hasStatusBar) {
         outInsets.setEmpty();
 
         // Navigation bar and status bar.
         computeNonDecorInsets(res, displayRotation, displayWidth, displayHeight, displayCutout,
-                uiMode, outInsets, hasNavigationBar);
+                insetsState, uiMode, outInsets, hasNavigationBar);
         convertNonDecorInsetsToStableInsets(res, outInsets, displayWidth, displayHeight,
                 hasStatusBar);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index e775d7d..bb40f67 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -18,11 +18,16 @@
 
 import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
 import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
 
 import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END;
 import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START;
+import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
+import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -32,6 +37,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.SurfaceControl;
 import android.view.WindowInsets;
@@ -81,6 +87,7 @@
     private final int mDividerInsets;
     private final int mDividerSize;
 
+    private final Rect mTempRect = new Rect();
     private final Rect mRootBounds = new Rect();
     private final Rect mDividerBounds = new Rect();
     private final Rect mBounds1 = new Rect();
@@ -89,6 +96,7 @@
     private final SplitWindowManager mSplitWindowManager;
     private final DisplayImeController mDisplayImeController;
     private final ImePositionProcessor mImePositionProcessor;
+    private final DismissingParallaxPolicy mDismissingParallaxPolicy;
     private final ShellTaskOrganizer mTaskOrganizer;
 
     private Context mContext;
@@ -111,6 +119,7 @@
                 windowName, mContext, configuration, parentContainerCallbacks);
         mTaskOrganizer = taskOrganizer;
         mImePositionProcessor = new ImePositionProcessor(mContext.getDisplayId());
+        mDismissingParallaxPolicy = new DismissingParallaxPolicy();
 
         final Resources resources = context.getResources();
         mDividerWindowWidth = resources.getDimensionPixelSize(
@@ -188,7 +197,8 @@
         mDividerBounds.set(mRootBounds);
         mBounds1.set(mRootBounds);
         mBounds2.set(mRootBounds);
-        if (isLandscape(mRootBounds)) {
+        final boolean isLandscape = isLandscape(mRootBounds);
+        if (isLandscape) {
             position += mRootBounds.left;
             mDividerBounds.left = position - mDividerInsets;
             mDividerBounds.right = mDividerBounds.left + mDividerWindowWidth;
@@ -201,6 +211,7 @@
             mBounds1.bottom = position;
             mBounds2.top = mBounds1.bottom + mDividerSize;
         }
+        mDismissingParallaxPolicy.applyDividerPosition(position, isLandscape);
     }
 
     /** Inflates {@link DividerView} on the root surface. */
@@ -240,6 +251,7 @@
     /** Resets divider position. */
     public void resetDividerPosition() {
         mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
+        mSplitWindowManager.setResizingSplits(false);
         updateBounds(mDividePosition);
     }
 
@@ -333,30 +345,34 @@
     /** Apply recorded surface layout to the {@link SurfaceControl.Transaction}. */
     public void applySurfaceChanges(SurfaceControl.Transaction t, SurfaceControl leash1,
             SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
-        final Rect dividerBounds = mImePositionProcessor.adjustForIme(mDividerBounds);
-        final Rect bounds1 = mImePositionProcessor.adjustForIme(mBounds1);
-        final Rect bounds2 = mImePositionProcessor.adjustForIme(mBounds2);
         final SurfaceControl dividerLeash = getDividerLeash();
         if (dividerLeash != null) {
-            t.setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
-                    // Resets layer of divider bar to make sure it is always on top.
-                    .setLayer(dividerLeash, Integer.MAX_VALUE);
+            t.setPosition(dividerLeash, mDividerBounds.left, mDividerBounds.top);
+            // Resets layer of divider bar to make sure it is always on top.
+            t.setLayer(dividerLeash, Integer.MAX_VALUE);
+        }
+        t.setPosition(leash1, mBounds1.left, mBounds1.top)
+                .setWindowCrop(leash1, mBounds1.width(), mBounds1.height());
+        t.setPosition(leash2, mBounds2.left, mBounds2.top)
+                .setWindowCrop(leash2, mBounds2.width(), mBounds2.height());
+
+        if (mImePositionProcessor.adjustSurfaceLayoutForIme(
+                t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
+            return;
         }
 
-        t.setPosition(leash1, bounds1.left, bounds1.top)
-                .setWindowCrop(leash1, bounds1.width(), bounds1.height());
-
-        t.setPosition(leash2, bounds2.left, bounds2.top)
-                .setWindowCrop(leash2, bounds2.width(), bounds2.height());
-
-        mImePositionProcessor.applySurfaceDimValues(t, dimLayer1, dimLayer2);
+        mDismissingParallaxPolicy.adjustDismissingSurface(t, leash1, leash2, dimLayer1, dimLayer2);
     }
 
     /** Apply recorded task layout to the {@link WindowContainerTransaction}. */
     public void applyTaskChanges(WindowContainerTransaction wct,
             ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
-        wct.setBounds(task1.token, mImePositionProcessor.adjustForIme(mBounds1))
-                .setBounds(task2.token, mImePositionProcessor.adjustForIme(mBounds2));
+        if (mImePositionProcessor.applyTaskLayoutForIme(wct, task1.token, task2.token)) {
+            return;
+        }
+
+        wct.setBounds(task1.token, mBounds1)
+                .setBounds(task2.token, mBounds2);
     }
 
     /**
@@ -376,23 +392,22 @@
             wct.setScreenSizeDp(taskInfo2.token,
                     SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
         } else {
-            final Rect bounds = new Rect();
-            bounds.set(taskInfo1.configuration.windowConfiguration.getBounds());
-            bounds.offset(offsetX, offsetY);
-            wct.setBounds(taskInfo1.token, bounds);
-            bounds.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
-            bounds.offset(offsetX, offsetY);
-            wct.setAppBounds(taskInfo1.token, bounds);
+            mTempRect.set(taskInfo1.configuration.windowConfiguration.getBounds());
+            mTempRect.offset(offsetX, offsetY);
+            wct.setBounds(taskInfo1.token, mTempRect);
+            mTempRect.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
+            mTempRect.offset(offsetX, offsetY);
+            wct.setAppBounds(taskInfo1.token, mTempRect);
             wct.setScreenSizeDp(taskInfo1.token,
                     taskInfo1.configuration.screenWidthDp,
                     taskInfo1.configuration.screenHeightDp);
 
-            bounds.set(taskInfo2.configuration.windowConfiguration.getBounds());
-            bounds.offset(offsetX, offsetY);
-            wct.setBounds(taskInfo2.token, bounds);
-            bounds.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
-            bounds.offset(offsetX, offsetY);
-            wct.setAppBounds(taskInfo2.token, bounds);
+            mTempRect.set(taskInfo2.configuration.windowConfiguration.getBounds());
+            mTempRect.offset(offsetX, offsetY);
+            wct.setBounds(taskInfo2.token, mTempRect);
+            mTempRect.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
+            mTempRect.offset(offsetX, offsetY);
+            wct.setAppBounds(taskInfo2.token, mTempRect);
             wct.setScreenSizeDp(taskInfo2.token,
                     taskInfo2.configuration.screenWidthDp,
                     taskInfo2.configuration.screenHeightDp);
@@ -428,6 +443,106 @@
         int getSplitItemPosition(WindowContainerToken token);
     }
 
+    /**
+     * Calculates and applies proper dismissing parallax offset and dimming value to hint users
+     * dismissing gesture.
+     */
+    private class DismissingParallaxPolicy {
+        // The current dismissing side.
+        int mDismissingSide = DOCKED_INVALID;
+
+        // The parallax offset to hint the dismissing side and progress.
+        final Point mDismissingParallaxOffset = new Point();
+
+        // The dimming value to hint the dismissing side and progress.
+        float mDismissingDimValue = 0.0f;
+
+        /**
+         * Applies a parallax to the task to hint dismissing progress.
+         *
+         * @param position the split position to apply dismissing parallax effect
+         * @param isLandscape indicates whether it's splitting horizontally or vertically
+         */
+        void applyDividerPosition(int position, boolean isLandscape) {
+            mDismissingSide = DOCKED_INVALID;
+            mDismissingParallaxOffset.set(0, 0);
+            mDismissingDimValue = 0;
+
+            int totalDismissingDistance = 0;
+            if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) {
+                mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP;
+                totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position
+                                - mDividerSnapAlgorithm.getFirstSplitTarget().position;
+            } else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) {
+                mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM;
+                totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position
+                                - mDividerSnapAlgorithm.getDismissEndTarget().position;
+            }
+
+            if (mDismissingSide != DOCKED_INVALID) {
+                float fraction = Math.max(0,
+                        Math.min(mDividerSnapAlgorithm.calculateDismissingFraction(position), 1f));
+                mDismissingDimValue = DIM_INTERPOLATOR.getInterpolation(fraction);
+                fraction = calculateParallaxDismissingFraction(fraction, mDismissingSide);
+                if (isLandscape) {
+                    mDismissingParallaxOffset.x = (int) (fraction * totalDismissingDistance);
+                } else {
+                    mDismissingParallaxOffset.y = (int) (fraction * totalDismissingDistance);
+                }
+            }
+        }
+
+        /**
+         * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
+         * slowing down parallax effect
+         */
+        private float calculateParallaxDismissingFraction(float fraction, int dockSide) {
+            float result = SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+
+            // Less parallax at the top, just because.
+            if (dockSide == WindowManager.DOCKED_TOP) {
+                result /= 2f;
+            }
+            return result;
+        }
+
+        /** Applies parallax offset and dimming value to the root surface at the dismissing side. */
+        boolean adjustDismissingSurface(SurfaceControl.Transaction t,
+                SurfaceControl leash1, SurfaceControl leash2,
+                SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
+            SurfaceControl targetLeash, targetDimLayer;
+            switch (mDismissingSide) {
+                case DOCKED_TOP:
+                case DOCKED_LEFT:
+                    targetLeash = leash1;
+                    targetDimLayer = dimLayer1;
+                    mTempRect.set(mBounds1);
+                    break;
+                case DOCKED_BOTTOM:
+                case DOCKED_RIGHT:
+                    targetLeash = leash2;
+                    targetDimLayer = dimLayer2;
+                    mTempRect.set(mBounds2);
+                    break;
+                case DOCKED_INVALID:
+                default:
+                    t.setAlpha(dimLayer1, 0).hide(dimLayer1);
+                    t.setAlpha(dimLayer2, 0).hide(dimLayer2);
+                    return false;
+            }
+
+            t.setPosition(targetLeash,
+                    mTempRect.left + mDismissingParallaxOffset.x,
+                    mTempRect.top + mDismissingParallaxOffset.y);
+            // Transform the screen-based split bounds to surface-based crop bounds.
+            mTempRect.offsetTo(-mDismissingParallaxOffset.x, -mDismissingParallaxOffset.y);
+            t.setWindowCrop(targetLeash, mTempRect);
+            t.setAlpha(targetDimLayer, mDismissingDimValue)
+                    .setVisibility(targetDimLayer, mDismissingDimValue > 0.001f);
+            return true;
+        }
+    }
+
     /** Records IME top offset changes and updates SplitLayout correspondingly. */
     private class ImePositionProcessor implements DisplayImeController.ImePositionProcessor {
         /**
@@ -558,24 +673,61 @@
             return start + (end - start) * progress;
         }
 
-        private void reset() {
+        void reset() {
             mImeShown = false;
             mYOffsetForIme = mLastYOffset = mTargetYOffset = 0;
             mDimValue1 = mLastDim1 = mTargetDim1 = 0.0f;
             mDimValue2 = mLastDim2 = mTargetDim2 = 0.0f;
         }
 
-        /* Adjust bounds with IME offset. */
-        private Rect adjustForIme(Rect bounds) {
-            final Rect temp = new Rect(bounds);
-            if (mYOffsetForIme != 0) temp.offset(0, mYOffsetForIme);
-            return temp;
+        /**
+         * Applies adjusted task layout for showing IME.
+         *
+         * @return {@code false} if there's no need to adjust, otherwise {@code true}
+         */
+        boolean applyTaskLayoutForIme(WindowContainerTransaction wct,
+                WindowContainerToken token1, WindowContainerToken token2) {
+            if (mYOffsetForIme == 0) return false;
+
+            mTempRect.set(mBounds1);
+            mTempRect.offset(0, mYOffsetForIme);
+            wct.setBounds(token1, mTempRect);
+
+            mTempRect.set(mBounds2);
+            mTempRect.offset(0, mYOffsetForIme);
+            wct.setBounds(token2, mTempRect);
+
+            return true;
         }
 
-        private void applySurfaceDimValues(SurfaceControl.Transaction t, SurfaceControl dimLayer1,
-                SurfaceControl dimLayer2) {
+        /**
+         * Adjusts surface layout while showing IME.
+         *
+         * @return {@code false} if there's no need to adjust, otherwise {@code true}
+         */
+        boolean adjustSurfaceLayoutForIme(SurfaceControl.Transaction t,
+                SurfaceControl dividerLeash, SurfaceControl leash1, SurfaceControl leash2,
+                SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
+            if (mYOffsetForIme == 0) return false;
+
+            if (dividerLeash != null) {
+                mTempRect.set(mDividerBounds);
+                mTempRect.offset(0, mYOffsetForIme);
+                t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
+            }
+
+            mTempRect.set(mBounds1);
+            mTempRect.offset(0, mYOffsetForIme);
+            t.setPosition(leash1, mTempRect.left, mTempRect.top);
+
+            mTempRect.set(mBounds2);
+            mTempRect.offset(0, mYOffsetForIme);
+            t.setPosition(leash2, mTempRect.left, mTempRect.top);
+
             t.setAlpha(dimLayer1, mDimValue1).setVisibility(dimLayer1, mDimValue1 > 0.001f);
             t.setAlpha(dimLayer2, mDimValue2).setVisibility(dimLayer2, mDimValue2 > 0.001f);
+
+            return true;
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
index 9bed40d..067f808 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java
@@ -20,6 +20,8 @@
 import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
 import static android.view.WindowManager.DOCKED_RIGHT;
 
+import static com.android.wm.shell.animation.Interpolators.DIM_INTERPOLATOR;
+import static com.android.wm.shell.animation.Interpolators.SLOWDOWN_INTERPOLATOR;
 import static com.android.wm.shell.common.split.DividerView.TOUCH_ANIMATION_DURATION;
 import static com.android.wm.shell.common.split.DividerView.TOUCH_RELEASE_ANIMATION_DURATION;
 
@@ -100,10 +102,6 @@
     private static final float MINIMIZE_DOCK_SCALE = 0f;
     private static final float ADJUSTED_FOR_IME_SCALE = 0.5f;
 
-    private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
-            new PathInterpolator(0.5f, 1f, 0.5f, 1f);
-    private static final PathInterpolator DIM_INTERPOLATOR =
-            new PathInterpolator(.23f, .87f, .52f, -0.11f);
     private static final Interpolator IME_ADJUST_INTERPOLATOR =
             new PathInterpolator(0.2f, 0f, 0.1f, 1f);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 29326ec..2286598 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -360,7 +360,7 @@
                 createIconDrawable(iconDrawable, false);
             } else {
                 final float iconScale = (float) mIconSize / (float) mDefaultIconSize;
-                final int densityDpi = mContext.getResources().getDisplayMetrics().densityDpi;
+                final int densityDpi = mContext.getResources().getConfiguration().densityDpi;
                 final int scaledIconDpi =
                         (int) (0.5f + iconScale * densityDpi * NO_BACKGROUND_SCALE);
                 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "getIcon");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index fc7c86d..52a3ac5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -52,6 +52,7 @@
 import android.view.SurfaceControlViewHost;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.widget.FrameLayout;
 import android.window.SplashScreenView;
 import android.window.SplashScreenView.SplashScreenViewParcelable;
@@ -115,6 +116,7 @@
     @VisibleForTesting
     final SplashscreenContentDrawer mSplashscreenContentDrawer;
     private Choreographer mChoreographer;
+    private final WindowManagerGlobal mWindowManagerGlobal;
 
     /**
      * @param splashScreenExecutor The thread used to control add and remove starting window.
@@ -126,6 +128,8 @@
         mSplashScreenExecutor = splashScreenExecutor;
         mSplashscreenContentDrawer = new SplashscreenContentDrawer(mContext, pool);
         mSplashScreenExecutor.execute(() -> mChoreographer = Choreographer.getInstance());
+        mWindowManagerGlobal = WindowManagerGlobal.getInstance();
+        mDisplayManager.getDisplay(DEFAULT_DISPLAY);
     }
 
     private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
@@ -137,21 +141,8 @@
     private final SparseArray<SurfaceControlViewHost> mAnimatedSplashScreenSurfaceHosts =
             new SparseArray<>(1);
 
-    /** Obtain proper context for showing splash screen on the provided display. */
-    private Context getDisplayContext(Context context, int displayId) {
-        if (displayId == DEFAULT_DISPLAY) {
-            // The default context fits.
-            return context;
-        }
-
-        final Display targetDisplay = mDisplayManager.getDisplay(displayId);
-        if (targetDisplay == null) {
-            // Failed to obtain the non-default display where splash screen should be shown,
-            // lets not show at all.
-            return null;
-        }
-
-        return context.createDisplayContext(targetDisplay);
+    private Display getDisplay(int displayId) {
+        return mDisplayManager.getDisplay(displayId);
     }
 
     private int getSplashScreenTheme(int splashScreenThemeResId, ActivityInfo activityInfo) {
@@ -186,13 +177,11 @@
                     + " suggestType=" + suggestType);
         }
 
-        // Obtain proper context to launch on the right display.
-        final Context displayContext = getDisplayContext(context, displayId);
-        if (displayContext == null) {
+        final Display display = getDisplay(displayId);
+        if (display == null) {
             // Can't show splash screen on requested display, so skip showing at all.
             return;
         }
-        context = displayContext;
         if (theme != context.getThemeResId()) {
             try {
                 context = context.createPackageContextAsUser(activityInfo.packageName,
@@ -330,10 +319,8 @@
         };
         mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId,
                 viewSupplier::setView);
-
         try {
-            final WindowManager wm = context.getSystemService(WindowManager.class);
-            if (addWindow(taskId, appToken, rootLayout, wm, params, suggestType)) {
+            if (addWindow(taskId, appToken, rootLayout, display, params, suggestType)) {
                 // We use the splash screen worker thread to create SplashScreenView while adding
                 // the window, as otherwise Choreographer#doFrame might be delayed on this thread.
                 // And since Choreographer#doFrame won't happen immediately after adding the window,
@@ -508,12 +495,14 @@
         viewHost.getView().post(viewHost::release);
     }
 
-    protected boolean addWindow(int taskId, IBinder appToken, View view, WindowManager wm,
+    protected boolean addWindow(int taskId, IBinder appToken, View view, Display display,
             WindowManager.LayoutParams params, @StartingWindowType int suggestType) {
         boolean shouldSaveView = true;
+        final Context context = view.getContext();
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addRootView");
-            wm.addView(view, params);
+            mWindowManagerGlobal.addView(view, params, display,
+                    null /* parentWindow */, context.getUserId());
         } catch (WindowManager.BadTokenException e) {
             // ignore
             Slog.w(TAG, appToken + " already running, starting window not displayed. "
@@ -521,9 +510,9 @@
             shouldSaveView = false;
         } finally {
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-            if (view != null && view.getParent() == null) {
+            if (view.getParent() == null) {
                 Slog.w(TAG, "view not successfully added to wm, removing view");
-                wm.removeViewImmediate(view);
+                mWindowManagerGlobal.removeView(view, true /* immediate */);
                 shouldSaveView = false;
             }
         }
@@ -587,10 +576,7 @@
         if (hideView) {
             decorView.setVisibility(View.GONE);
         }
-        final WindowManager wm = decorView.getContext().getSystemService(WindowManager.class);
-        if (wm != null) {
-            wm.removeView(decorView);
-        }
+        mWindowManagerGlobal.removeView(decorView, false /* immediate */);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
index ef046d4..b888450 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -58,7 +58,7 @@
         mT = mock(SurfaceControl.Transaction.class);
         mMock = mock(IInputMethodManager.class);
         mExecutor = spy(Runnable::run);
-        mPerDisplay = new DisplayImeController(null, null, mExecutor, new TransactionPool() {
+        mPerDisplay = new DisplayImeController(null, null, null, mExecutor, new TransactionPool() {
             @Override
             public SurfaceControl.Transaction acquire() {
                 return mT;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
new file mode 100644
index 0000000..b66c2b4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.wm.shell.common;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.os.RemoteException;
+import android.util.SparseArray;
+import android.view.IDisplayWindowInsetsController;
+import android.view.IWindowManager;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.TestShellExecutor;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+@SmallTest
+public class DisplayInsetsControllerTest {
+
+    private static final int SECOND_DISPLAY = DEFAULT_DISPLAY + 10;
+
+    @Mock
+    private IWindowManager mWm;
+    @Mock
+    private DisplayController mDisplayController;
+    private DisplayInsetsController mController;
+    private SparseArray<IDisplayWindowInsetsController> mInsetsControllersByDisplayId;
+    private TestShellExecutor mExecutor;
+
+    private ArgumentCaptor<Integer> mDisplayIdCaptor;
+    private ArgumentCaptor<IDisplayWindowInsetsController> mInsetsControllerCaptor;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mExecutor = new TestShellExecutor();
+        mInsetsControllersByDisplayId = new SparseArray<>();
+        mDisplayIdCaptor =  ArgumentCaptor.forClass(Integer.class);
+        mInsetsControllerCaptor = ArgumentCaptor.forClass(IDisplayWindowInsetsController.class);
+        mController = new DisplayInsetsController(mWm, mDisplayController, mExecutor);
+        addDisplay(DEFAULT_DISPLAY);
+    }
+
+    @Test
+    public void testOnDisplayAdded_setsDisplayWindowInsetsControllerOnWMService()
+            throws RemoteException {
+        addDisplay(SECOND_DISPLAY);
+
+        verify(mWm).setDisplayWindowInsetsController(eq(SECOND_DISPLAY), notNull());
+    }
+
+    @Test
+    public void testOnDisplayRemoved_unsetsDisplayWindowInsetsControllerInWMService()
+            throws RemoteException {
+        addDisplay(SECOND_DISPLAY);
+        removeDisplay(SECOND_DISPLAY);
+
+        verify(mWm).setDisplayWindowInsetsController(SECOND_DISPLAY, null);
+    }
+
+    @Test
+    public void testPerDisplayListenerCallback() throws RemoteException {
+        TrackedListener defaultListener = new TrackedListener();
+        TrackedListener secondListener = new TrackedListener();
+        addDisplay(SECOND_DISPLAY);
+        mController.addInsetsChangedListener(DEFAULT_DISPLAY, defaultListener);
+        mController.addInsetsChangedListener(SECOND_DISPLAY, secondListener);
+
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).topFocusedWindowChanged(null);
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsChanged(null);
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsControlChanged(null, null);
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).showInsets(0, false);
+        mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).hideInsets(0, false);
+        mExecutor.flushAll();
+
+        assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
+        assertTrue(defaultListener.insetsChangedCount == 1);
+        assertTrue(defaultListener.insetsControlChangedCount == 1);
+        assertTrue(defaultListener.showInsetsCount == 1);
+        assertTrue(defaultListener.hideInsetsCount == 1);
+
+        assertTrue(secondListener.topFocusedWindowChangedCount == 0);
+        assertTrue(secondListener.insetsChangedCount == 0);
+        assertTrue(secondListener.insetsControlChangedCount == 0);
+        assertTrue(secondListener.showInsetsCount == 0);
+        assertTrue(secondListener.hideInsetsCount == 0);
+
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).topFocusedWindowChanged(null);
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsChanged(null);
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsControlChanged(null, null);
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).showInsets(0, false);
+        mInsetsControllersByDisplayId.get(SECOND_DISPLAY).hideInsets(0, false);
+        mExecutor.flushAll();
+
+        assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
+        assertTrue(defaultListener.insetsChangedCount == 1);
+        assertTrue(defaultListener.insetsControlChangedCount == 1);
+        assertTrue(defaultListener.showInsetsCount == 1);
+        assertTrue(defaultListener.hideInsetsCount == 1);
+
+        assertTrue(secondListener.topFocusedWindowChangedCount == 1);
+        assertTrue(secondListener.insetsChangedCount == 1);
+        assertTrue(secondListener.insetsControlChangedCount == 1);
+        assertTrue(secondListener.showInsetsCount == 1);
+        assertTrue(secondListener.hideInsetsCount == 1);
+    }
+
+    private void addDisplay(int displayId) throws RemoteException {
+        mController.onDisplayAdded(displayId);
+        verify(mWm, times(mInsetsControllersByDisplayId.size() + 1))
+                .setDisplayWindowInsetsController(mDisplayIdCaptor.capture(),
+                        mInsetsControllerCaptor.capture());
+        List<Integer> displayIds = mDisplayIdCaptor.getAllValues();
+        List<IDisplayWindowInsetsController> insetsControllers =
+                mInsetsControllerCaptor.getAllValues();
+        for (int i = 0; i < displayIds.size(); i++) {
+            mInsetsControllersByDisplayId.put(displayIds.get(i), insetsControllers.get(i));
+        }
+    }
+
+    private void removeDisplay(int displayId) {
+        mController.onDisplayRemoved(displayId);
+        mInsetsControllersByDisplayId.remove(displayId);
+    }
+
+    private static class TrackedListener implements
+            DisplayInsetsController.OnInsetsChangedListener {
+        int topFocusedWindowChangedCount = 0;
+        int insetsChangedCount = 0;
+        int insetsControlChangedCount = 0;
+        int showInsetsCount = 0;
+        int hideInsetsCount = 0;
+
+        @Override
+        public void topFocusedWindowChanged(String packageName) {
+            topFocusedWindowChangedCount++;
+        }
+
+        @Override
+        public void insetsChanged(InsetsState insetsState) {
+            insetsChangedCount++;
+        }
+
+        @Override
+        public void insetsControlChanged(InsetsState insetsState,
+                InsetsSourceControl[] activeControls) {
+            insetsControlChangedCount++;
+        }
+
+        @Override
+        public void showInsets(int types, boolean fromIme) {
+            showInsetsCount++;
+        }
+
+        @Override
+        public void hideInsets(int types, boolean fromIme) {
+            hideInsetsCount++;
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index d536adb..160b367 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -42,6 +42,7 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.testing.TestableContext;
+import android.view.Display;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
@@ -92,8 +93,8 @@
         }
 
         @Override
-        protected boolean addWindow(int taskId, IBinder appToken,
-                View view, WindowManager wm, WindowManager.LayoutParams params, int suggestType) {
+        protected boolean addWindow(int taskId, IBinder appToken, View view, Display display,
+                WindowManager.LayoutParams params, int suggestType) {
             // listen for addView
             mAddWindowForTask = taskId;
             mViewThemeResId = view.getContext().getThemeResId();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 84565e5..3762456 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -685,6 +685,7 @@
             // No remote stuff happening, so this can't be hit
         }
         DisplayController out = new DisplayController(mContext, mockWM, mMainExecutor);
+        out.initialize();
         try {
             displayListener[0].onDisplayAdded(DEFAULT_DISPLAY);
             mMainExecutor.flushAll();
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index acd8bce..d10e688 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -153,8 +153,7 @@
                     || update.state.surfaceHeight < desiredHeight) {
                 needApplyTransaction = true;
 
-                t.setSize(update.state.surfaceControl,
-                        desiredWidth, desiredHeight);
+                update.state.surfaceControl->updateDefaultBufferSize(desiredWidth, desiredHeight);
                 update.state.surfaceWidth = desiredWidth;
                 update.state.surfaceHeight = desiredHeight;
                 update.state.surfaceDrawn = false;
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 1e8b952..209903c 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -1084,6 +1084,12 @@
         mExtras = (extras == null) ? null : new Bundle(extras);
     }
 
+    /**
+     * Location equality is provided primarily for test purposes. Comparing locations for equality
+     * in production may indicate incorrect assumptions, and should be avoided whenever possible.
+     *
+     * <p>{@inheritDoc}
+     */
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -1121,7 +1127,17 @@
                 && (!hasBearingAccuracy() || Float.compare(location.mBearingAccuracyDegrees,
                 mBearingAccuracyDegrees) == 0)
                 && Objects.equals(mProvider, location.mProvider)
-                && Objects.equals(mExtras, location.mExtras);
+                && areExtrasEqual(mExtras, location.mExtras);
+    }
+
+    private static boolean areExtrasEqual(@Nullable Bundle extras1, @Nullable Bundle extras2) {
+        if ((extras1 == null || extras1.isEmpty()) && (extras2 == null || extras2.isEmpty())) {
+            return true;
+        } else if (extras1 == null || extras2 == null) {
+            return false;
+        } else {
+            return extras1.kindofEquals(extras2);
+        }
     }
 
     @Override
diff --git a/location/java/android/location/LocationListener.java b/location/java/android/location/LocationListener.java
index 35a4091..031642b 100644
--- a/location/java/android/location/LocationListener.java
+++ b/location/java/android/location/LocationListener.java
@@ -38,9 +38,9 @@
 public interface LocationListener {
 
     /**
-     * Called when the location has changed. A wakelock is held on behalf on the listener for some
-     * brief amount of time as this callback executes. If this callback performs long running
-     * operations, it is the client's responsibility to obtain their own wakelock.
+     * Called when the location has changed. A wakelock may be held on behalf on the listener for
+     * some brief amount of time as this callback executes. If this callback performs long running
+     * operations, it is the client's responsibility to obtain their own wakelock if necessary.
      *
      * @param location the updated location
      */
@@ -48,7 +48,7 @@
 
     /**
      * Called when the location has changed and locations are being delivered in batches. The
-     * default implementation calls through to ({@link #onLocationChanged(Location)} with all
+     * default implementation calls through to {@link #onLocationChanged(Location)} with all
      * locations in the batch. The list of locations is always guaranteed to be non-empty, and is
      * always guaranteed to be ordered from earliest location to latest location (so that the
      * earliest location in the batch is at index 0 in the list, and the latest location in the
@@ -76,6 +76,11 @@
      * This callback will never be invoked on Android Q and above, and providers can be considered
      * as always in the {@link LocationProvider#AVAILABLE} state.
      *
+     * <p class="note">Note that this method only has a default implementation on Android R and
+     * above, and this method must still be overridden in order to run successfully on Android
+     * versions below R. LocationListenerCompat from the compat libraries may be used to avoid the
+     * need to override for older platforms.
+     *
      * @deprecated This callback will never be invoked on Android Q and above.
      */
     @Deprecated
@@ -84,6 +89,11 @@
     /**
      * Called when a provider this listener is registered with becomes enabled.
      *
+     * <p class="note">Note that this method only has a default implementation on Android R and
+     * above, and this method must still be overridden in order to run successfully on Android
+     * versions below R. LocationListenerCompat from the compat libraries may be used to avoid the
+     * need to override for older platforms.
+     *
      * @param provider the name of the location provider
      */
     default void onProviderEnabled(@NonNull String provider) {}
@@ -92,6 +102,11 @@
      * Called when the provider this listener is registered with becomes disabled. If a provider is
      * disabled when this listener is registered, this callback will be invoked immediately.
      *
+     * <p class="note">Note that this method only has a default implementation on Android R and
+     * above, and this method must still be overridden in order to run successfully on Android
+     * versions below R. LocationListenerCompat from the compat libraries may be used to avoid the
+     * need to override for older platforms.
+     *
      * @param provider the name of the location provider
      */
     default void onProviderDisabled(@NonNull String provider) {}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 37e1415..72cddc9 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -16,14 +16,14 @@
 
 package android.media.projection;
 
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.hardware.display.VirtualDisplayConfig;
-import android.media.projection.IMediaProjection;
-import android.media.projection.IMediaProjectionCallback;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.ArrayMap;
@@ -106,7 +106,7 @@
         if (isSecure) {
             flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
         }
-        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+        final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
                 height, dpi);
         builder.setFlags(flags);
         if (surface != null) {
@@ -141,7 +141,7 @@
     public VirtualDisplay createVirtualDisplay(@NonNull String name,
             int width, int height, int dpi, int flags, @Nullable Surface surface,
             @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
-        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+        final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
                 height, dpi);
         builder.setFlags(flags);
         if (surface != null) {
@@ -151,6 +151,26 @@
     }
 
     /**
+     * Constructs a {@link VirtualDisplayConfig.Builder}, which will mirror the contents of a
+     * DisplayArea. The DisplayArea to mirror is from the DisplayArea the caller is launched on.
+     *
+     * @param name   The name of the virtual display, must be non-empty.
+     * @param width  The width of the virtual display in pixels. Must be greater than 0.
+     * @param height The height of the virtual display in pixels. Must be greater than 0.
+     * @param dpi    The density of the virtual display in dpi. Must be greater than 0.
+     * @return a config representing a VirtualDisplay
+     */
+    private VirtualDisplayConfig.Builder buildMirroredVirtualDisplay(@NonNull String name,
+            int width, int height, int dpi) {
+        Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+                TYPE_APPLICATION, null /* options */);
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
+                height, dpi);
+        builder.setWindowTokenClientToMirror(windowContext.getWindowContextToken());
+        return builder;
+    }
+
+    /**
      * Creates a {@link android.hardware.display.VirtualDisplay} to capture the
      * contents of the screen.
      *
diff --git a/packages/PackageInstaller/res/values-te/strings.xml b/packages/PackageInstaller/res/values-te/strings.xml
index dba1ab4..11e01c7 100644
--- a/packages/PackageInstaller/res/values-te/strings.xml
+++ b/packages/PackageInstaller/res/values-te/strings.xml
@@ -86,7 +86,7 @@
     <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"తెలియని యాప్‌లు మీ ఫోన్ పైన, వ్యక్తిగత డేటా పైన దాడి చేయడానికి ఎక్కువగా అవకాశం ఉంటుంది. ఈ యాప్‌ను ఇన్‌స్టాల్ చేయడం ద్వారా, దాని వినియోగంతో మీ ఫోన్‌కు ఏదైనా నష్టం జరిగితే లేదా మీ డేటాను కోల్పోతే అందుకు మీరే బాధ్యత వహిస్తారని అంగీకరిస్తున్నారు."</string>
     <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"మీ టాబ్లెట్ మరియు వ్యక్తిగత డేటాపై తెలియని యాప్‌లు దాడి చేయడానికి ఎక్కువ అవకాశం ఉంది. మీరు ఈ యాప్‌ను ఇన్‌స్టాల్ చేయడం ద్వారా, దీనిని ఉపయోగించడం వలన మీ టాబ్లెట్‌కు ఏదైనా హాని జరిగినా లేదా డేటా కోల్పోయినా బాధ్యత మీదేనని అంగీకరిస్తున్నారు."</string>
     <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"మీ టీవీ మరియు వ్యక్తిగత డేటాపై తెలియని యాప్‌లు దాడి చేయడానికి ఎక్కువ అవకాశం ఉంది. మీరు ఈ యాప్‌ను ఇన్‌స్టాల్ చేయడం ద్వారా, దీనిని ఉపయోగించడం వలన మీ టీవీకి ఏదైనా హాని జరిగినా లేదా డేటా కోల్పోయినా బాధ్యత మీదేనని అంగీకరిస్తున్నారు."</string>
-    <string name="anonymous_source_continue" msgid="4375745439457209366">"కొనసాగించు"</string>
+    <string name="anonymous_source_continue" msgid="4375745439457209366">"కొనసాగండి"</string>
     <string name="external_sources_settings" msgid="4046964413071713807">"సెట్టింగ్‌లు"</string>
     <string name="wear_app_channel" msgid="1960809674709107850">"Wear యాప్‌లను ఇన్‌స్టాల్/అన్‌ఇన్‌స్టాల్ చేస్తోంది"</string>
     <string name="app_installed_notification_channel_description" msgid="2695385797601574123">"యాప్ ఇన్‌స్టాల్ చేయబడిందనే నోటిఫికేషన్"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 881b76b..e397035 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -511,7 +511,7 @@
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"المنبّهات والتذكيرات"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"السماح بضبط المنبّهات والتذكيرات"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"المنبّهات والتذكيرات"</string>
-    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"عليك السماح لهذا التطبيق بضبط المنبّهات وتحديد مواعيد للإجراءات الحساسة زمنيًا. يسمح هذا الأذن بتشغيل التطبيق في الخلفية، ما قد يستهلك المزيد من شحن البطارية.\n\nإذا كان هذا الإذن غير مسموح به، لن تعمل الأحداث المستندة إلى وقت والمنبّهات الحالية التي يحدِّد هذا التطبيق موعدها."</string>
+    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"يمكنك السماح لهذا التطبيق بضبط المنبّهات وجدولة الإجراءات لتنفيذها في الوقت المناسب. ويسمح هذا الإذن بتشغيل التطبيق في الخلفية، ما قد يستهلك المزيد من البطارية.\n\nفي حال عدم تفعيل هذا الإذن، لن تعمل المنبهات الحالية والأحداث المستندة إلى الوقت المضبوطة في هذا التطبيق."</string>
     <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"جدول زمني، جدولة، منبّه، تذكير، ساعة"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"تفعيل"</string>
     <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"تفعيل ميزة \"عدم الإزعاج\""</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 7755cb7..048039f 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -426,7 +426,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Protanomalía (rojo-verde)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Tritanomalía (azul-amarillo)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Corrección de color"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajusta cómo se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; Ver colores con más exactitud&lt;/li&gt; &lt;li&gt; Quitar colores para tener un enfoque más claro&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Ajusta cómo se muestran los colores en tu dispositivo. Esto puede ser útil cuando quieres:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Ver colores con más exactitud&lt;/li&gt; &lt;li&gt;&amp;nbsp;Quitar colores para tener un enfoque más claro&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Reemplazado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante: aproximadamente <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index d835cb9..60469a1 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -507,7 +507,7 @@
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmid ja meeldetuletused"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Luba alarmide ja meeldetuletuste määramine"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmid ja meeldetuletused"</string>
-    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lubage sellel rakendusel määrata alarme ja ajastada kiire tähtajaga toiminguid. See võimaldab rakendusel töötada taustal, mistõttu võib akukasutus olla suurem.\n\nKui see luba on välja lülitatud, siis olemasolevad alarmid ja selle rakenduse ajastatud ajapõhised sündmused ei tööta."</string>
+    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lubage sellel rakendusel määrata alarme ja ajastada ajakriitilisi toiminguid. See võimaldab rakendusel töötada taustal, mistõttu võib akukasutus olla suurem.\n\nKui see luba on välja lülitatud, siis olemasolevad alarmid ja selle rakenduse ajastatud ajapõhised sündmused ei tööta."</string>
     <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ajakava, äratus, meeldetuletus, kell"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Lülita sisse"</string>
     <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Valiku Mitte segada sisselülitamine"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index bf9b72e..630000f 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -527,7 +527,7 @@
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"कनेक्ट करने में समस्या हो रही है. डिवाइस को बंद करके चालू करें"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"वायर वाला ऑडियो डिवाइस"</string>
     <string name="help_label" msgid="3528360748637781274">"सहायता और सुझाव"</string>
-    <string name="storage_category" msgid="2287342585424631813">"डिवाइस की मेमोरी"</string>
+    <string name="storage_category" msgid="2287342585424631813">"डिवाइस का स्टोरेज"</string>
     <string name="shared_data_title" msgid="1017034836800864953">"शेयर किया गया डेटा"</string>
     <string name="shared_data_summary" msgid="5516326713822885652">"शेयर किए गए डेटा को देखें और उसमें बदलाव करें"</string>
     <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"इस उपयोगकर्ता के साथ किसी तरह का डेटा शेयर नहीं किया गया है."</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 4b37650..c140308 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -507,7 +507,7 @@
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarm dan pengingat"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Izinkan menyetel alarm dan pengingat"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarm &amp; pengingat"</string>
-    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Izinkan aplikasi ini menyetel alarm dan menjadwalkan tindakan berjangka waktu. Hal ini memungkinkan aplikasi berjalan di latar belakang, sehingga mungkin menggunakan lebih banyak daya baterai.\n\nJika izin ini dinonaktifkan, alarm dan acara berjangka waktu yang dijadwalkan oleh aplikasi ini tidak akan berfungsi."</string>
+    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Izinkan aplikasi ini menyetel alarm dan menjadwalkan tindakan yang sensitif waktu. Hal ini memungkinkan aplikasi berjalan di latar belakang, sehingga mungkin menggunakan lebih banyak daya baterai.\n\nJika izin ini dinonaktifkan, alarm dan acara berbasis waktu yang dijadwalkan oleh aplikasi ini tidak akan berfungsi."</string>
     <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"jadwal, alarm, pengingat, jam"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktifkan"</string>
     <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktifkan mode Jangan Ganggu"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 71cc9a0..9f2d8a2 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -426,7 +426,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"פרוטנומליה (אדום-ירוק)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"טריטנומליה (כחול-צהוב)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"תיקון צבע"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"‏ניתן לשנות את האופן שבו צבעים מוצגים במכשיר. שינוי כזה עשוי לעזור:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt; להבחין בצבעים בצורה יותר מדויקת&lt;/li&gt; &lt;li&gt; להסיר צבעים מסוימים כדי להתמקד&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"‏ניתן לשנות את האופן שבו צבעים מוצגים במכשיר. שינוי כזה עשוי לעזור:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;להבחין בצבעים בצורה יותר מדויקת&lt;/li&gt; &lt;li&gt;&amp;nbsp;להסיר צבעים מסוימים כדי להתמקד&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 2576993..474ded9 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -426,7 +426,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"Протаномаль (улаан-ногоон)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"Тританомаль (цэнхэр-шар)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"Өнгө тохируулах"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Таны төхөөрөмж дээр өнгийг хэрхэн үзүүлэхийг тохируулна уу. Энэ нь танд дараахыг хийхийг хүссэн үед хэрэг болж магадгүй:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;Өнгийг илүү оновчтой харах&lt;/li&gt; &lt;li&gt;Танд төвлөрөхөд туслахын тулд өнгийг хасах&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"Таны төхөөрөмж дээр өнгийг хэрхэн үзүүлэхийг тохируулна уу. Энэ нь танд дараахыг хийхийг хүссэн үед хэрэг болж магадгүй:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;Өнгийг илүү оновчтой харах&lt;/li&gt; &lt;li&gt;&amp;nbsp;Танд төвлөрөхөд туслахын тулд өнгийг хасах&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 78b35aa..e39b420 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -507,7 +507,7 @@
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"Alarmet dhe alarmet rikujtuese"</string>
     <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Lejo caktimin e alarmeve dhe alarmeve rikujtuese"</string>
     <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmet dhe alarmet rikujtuese"</string>
-    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lejo që ky aplikacion të caktojë alarmet dhe të planifikojë veprime që kanë një afat të caktuar. Kjo lejon që aplikacioni të ekzekutohet në sfond, gjë që mund të përdorë më shumë bateri.\n\nNëse kjo leje është caktuar si joaktive, alarmet ekzistuese dhe ngjarjet me bazë kohore të planifikuara nga ky apliikacion nuk do të funksionojnë."</string>
+    <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lejo që ky aplikacion të caktojë alarmet dhe të planifikojë veprime që kanë një afat të caktuar. Kjo mundëson që aplikacioni të ekzekutohet në sfond, gjë që mund të përdorë më shumë bateri.\n\nNëse kjo leje është caktuar si joaktive, alarmet ekzistuese dhe ngjarjet në bazë kohore të planifikuara nga ky aplikacion nuk do të funksionojnë."</string>
     <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"planifiko, alarm, alarm rikujtues, ora"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktivizo"</string>
     <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktivizo \"Mos shqetëso\""</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 6255d41..4a3b32a 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -98,7 +98,7 @@
     <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"செவித்துணை கருவிகளுடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"மீடியா ஆடியோவுடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"மொபைல் ஆடியோவுடன் இணைக்கப்பட்டது"</string>
-    <string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"கோப்பைப் பரிமாற்றும் சேவையகத்துடன் இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"ஃபைலைப் பரிமாற்றும் சேவையகத்துடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"வரைபடத்துடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"SAP உடன் இணைக்கப்பட்டது"</string>
     <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"கோப்பு இடமாற்றும் சேவையகத்துடன் இணைக்கப்படவில்லை"</string>
@@ -426,7 +426,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"நிறம் அடையாளங்காண முடியாமை (சிவப்பு-பச்சை)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"நிறம் அடையாளங்காண முடியாமை (நீலம்-மஞ்சள்)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"வண்ணத்திருத்தம்"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"சாதனத்தில் வண்ணங்கள் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம். இதன் மூலம் நீங்கள் விரும்பும்போதெல்லாம்:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;வண்ணங்களை மிகத் தெளிவாகப் பார்க்கலாம்&lt;/li&gt; &lt;li&gt;கவனம் சிதறாமல் இருக்க வண்ணங்களை நீக்கலாம்&lt;/li&gt; &lt;/ol&gt;"</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="2333641630205214702">"சாதனத்தில் வண்ணங்கள் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம். இதன் மூலம் நீங்கள் விரும்பும்போதெல்லாம்:&lt;br/&gt;&lt;br/&gt; &lt;ol&gt; &lt;li&gt;&amp;nbsp;வண்ணங்களை மிகத் தெளிவாகப் பார்க்கலாம்&lt;/li&gt; &lt;li&gt;&amp;nbsp;கவனம் சிதறாமல் இருக்க வண்ணங்களை நீக்கலாம்&lt;/li&gt; &lt;/ol&gt;"</string>
     <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
     <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
     <string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 4f74d24..9a1e4f4 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -33,12 +33,12 @@
     <string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"\'<xliff:g id="AP_NAME">%1$s</xliff:g>\'కు కనెక్ట్ చేయడం సాధ్యపడదు"</string>
     <string name="wifi_check_password_try_again" msgid="8817789642851605628">"పాస్‌వర్డ్‌ను చెక్ చేసి, మళ్లీ ప్రయత్నించండి"</string>
     <string name="wifi_not_in_range" msgid="1541760821805777772">"పరిధిలో లేదు"</string>
-    <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"స్వయంచాలకంగా కనెక్ట్ కాదు"</string>
+    <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ఆటోమేటిక్‌గా కనెక్ట్ కాదు"</string>
     <string name="wifi_no_internet" msgid="1774198889176926299">"ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
     <string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
     <string name="connected_to_metered_access_point" msgid="9179693207918156341">"డేటా నియంత్రణ నెట్‌వర్క్‌కు కనెక్ట్ చేయబడింది"</string>
-    <string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
-    <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"నెట్‌వర్క్ రేటింగ్ ప్రదాత ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
+    <string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ద్వారా ఆటోమేటిక్‌గా కనెక్ట్ చేయబడింది"</string>
+    <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"నెట్‌వర్క్ రేటింగ్ ప్రదాత ద్వారా ఆటోమేటిక్‌గా కనెక్ట్ చేయబడింది"</string>
     <string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
     <string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా కనెక్ట్ చేయబడింది"</string>
     <string name="available_via_passpoint" msgid="1716000261192603682">"%1$s ద్వారా అందుబాటులో ఉంది"</string>
@@ -83,7 +83,7 @@
     <string name="bluetooth_battery_level_untethered" msgid="4002282355111504349">"L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> బ్యాటరీ, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> బ్యాటరీ"</string>
     <string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"యాక్టివ్‌గా ఉంది"</string>
     <string name="bluetooth_profile_a2dp" msgid="4632426382762851724">"మీడియా ఆడియో"</string>
-    <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ఫోన్ కాల్‌లు"</string>
+    <string name="bluetooth_profile_headset" msgid="5395952236133499331">"ఫోన్ కాల్స్‌"</string>
     <string name="bluetooth_profile_opp" msgid="6692618568149493430">"ఫైల్ బదిలీ"</string>
     <string name="bluetooth_profile_hid" msgid="2969922922664315866">"ఇన్‌పుట్ పరికరం"</string>
     <string name="bluetooth_profile_pan" msgid="1006235139308318188">"ఇంటర్నెట్ యాక్సెస్"</string>
@@ -301,7 +301,7 @@
     <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"ఎల్లప్పుడూ మొబైల్ డేటాను యాక్టివ్‌గా ఉంచు, Wi‑Fi యాక్టివ్‌గా ఉన్నా కూడా (వేగవంతమైన నెట్‌వర్క్ మార్పు కోసం)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"అందుబాటులో ఉంటే టెథెరింగ్ హార్డ్‌వేర్ వేగవృద్ధిని ఉపయోగించండి"</string>
     <string name="adb_warning_title" msgid="7708653449506485728">"USB డీబగ్గింగ్‌ను అనుమతించాలా?"</string>
-    <string name="adb_warning_message" msgid="8145270656419669221">"USB డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్ మరియు మీ పరికరం మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో అనువర్తనాలను ఇన్‌స్టాల్ చేయడానికి మరియు లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
+    <string name="adb_warning_message" msgid="8145270656419669221">"USB డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్ మరియు మీ పరికరం మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో యాప్‌లను ఇన్‌స్టాల్ చేయడానికి మరియు లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
     <string name="adbwifi_warning_title" msgid="727104571653031865">"వైర్‌లెస్ డీబగ్గింగ్‌ను అనుమతించాలా?"</string>
     <string name="adbwifi_warning_message" msgid="8005936574322702388">"వైర్‌లెస్ డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్, పరికరాల మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో యాప్‌లను ఇన్‌స్టాల్ చేయడానికి, లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
     <string name="adb_keys_warning_message" msgid="2968555274488101220">"మీరు గతంలో ప్రామాణీకరించిన అన్ని కంప్యూటర్‌ల నుండి USB డీబగ్గింగ్‌కు ప్రాప్యతను ఉపసంహరించాలా?"</string>
@@ -541,8 +541,8 @@
     <string name="accessor_expires_text" msgid="4625619273236786252">"లీజు గడువు <xliff:g id="DATE">%s</xliff:g>తో ముగుస్తుంది"</string>
     <string name="delete_blob_text" msgid="2819192607255625697">"షేర్ చేసిన డేటాను తొలగించు"</string>
     <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"మీరు ఖచ్చితంగా ఈ షేర్ చేసిన డేటాను తొలగించాలనుకుంటున్నారా?"</string>
-    <string name="user_add_user_item_summary" msgid="5748424612724703400">"వినియోగదారులు వారి స్వంత అనువర్తనాలను మరియు కంటెంట్‌ను కలిగి ఉన్నారు"</string>
-    <string name="user_add_profile_item_summary" msgid="5418602404308968028">"మీరు మీ ఖాతా నుండి అనువర్తనాలకు మరియు కంటెంట్‌కు ప్రాప్యతను పరిమితం చేయవచ్చు"</string>
+    <string name="user_add_user_item_summary" msgid="5748424612724703400">"వినియోగదారులు వారి స్వంత యాప్‌లను మరియు కంటెంట్‌ను కలిగి ఉన్నారు"</string>
+    <string name="user_add_profile_item_summary" msgid="5418602404308968028">"మీరు మీ ఖాతా నుండి యాప్‌లకు మరియు కంటెంట్‌కు ప్రాప్యతను పరిమితం చేయవచ్చు"</string>
     <string name="user_add_user_item_title" msgid="2394272381086965029">"యూజర్"</string>
     <string name="user_add_profile_item_title" msgid="3111051717414643029">"పరిమితం చేయబడిన ప్రొఫైల్"</string>
     <string name="user_add_user_title" msgid="5457079143694924885">"కొత్త వినియోగదారుని జోడించాలా?"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index ed8d524..3c43f4a6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -15,7 +15,6 @@
  */
 package com.android.settingslib.media;
 
-import static android.media.MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK;
 import static android.media.MediaRoute2Info.TYPE_BLUETOOTH_A2DP;
 import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER;
 import static android.media.MediaRoute2Info.TYPE_DOCK;
@@ -388,34 +387,7 @@
 
     @TargetApi(Build.VERSION_CODES.R)
     boolean shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo) {
-        if (sessionInfo == null) {
-            Log.w(TAG, "shouldEnableVolumeSeekBar() package name is null or empty!");
-            return false;
-        }
-        final List<MediaRoute2Info> mediaRoute2Infos =
-                mRouterManager.getSelectedRoutes(sessionInfo);
-        // More than one selected route
-        if (mediaRoute2Infos.size() > 1) {
-            if (DEBUG) {
-                Log.d(TAG, "shouldEnableVolumeSeekBar() package name : "
-                        + sessionInfo.getClientPackageName()
-                        + ", mediaRoute2Infos.size() " + mediaRoute2Infos.size());
-            }
-            return false;
-        }
-        // Route contains group feature
-        for (MediaRoute2Info mediaRoute2Info : mediaRoute2Infos) {
-            final List<String> features = mediaRoute2Info.getFeatures();
-            if (features.contains(FEATURE_REMOTE_GROUP_PLAYBACK)) {
-                if (DEBUG) {
-                    Log.d(TAG, "shouldEnableVolumeSeekBar() package name : "
-                            + mediaRoute2Info.getClientPackageName()
-                            + "contain group playback ");
-                }
-                return false;
-            }
-        }
-        return true;
+        return false;
     }
 
     private void refreshDevices() {
diff --git a/packages/Shell/res/values-te/strings.xml b/packages/Shell/res/values-te/strings.xml
index fc49f07..50b5c85 100644
--- a/packages/Shell/res/values-te/strings.xml
+++ b/packages/Shell/res/values-te/strings.xml
@@ -18,30 +18,30 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"షెల్"</string>
     <string name="bugreport_notification_channel" msgid="2574150205913861141">"బగ్ రిపోర్ట్స్"</string>
-    <string name="bugreport_in_progress_title" msgid="4311705936714972757">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> ఉత్పాదించబడుతోంది"</string>
-    <string name="bugreport_finished_title" msgid="4429132808670114081">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> సంగ్రహించబడింది"</string>
-    <string name="bugreport_updating_title" msgid="4423539949559634214">"బగ్ నివేదికకు వివరాలను జోడిస్తోంది"</string>
+    <string name="bugreport_in_progress_title" msgid="4311705936714972757">"బగ్ రిపోర్ట్‌ <xliff:g id="ID">#%d</xliff:g> ఉత్పాదించబడుతోంది"</string>
+    <string name="bugreport_finished_title" msgid="4429132808670114081">"బగ్ రిపోర్ట్‌ <xliff:g id="ID">#%d</xliff:g> సంగ్రహించబడింది"</string>
+    <string name="bugreport_updating_title" msgid="4423539949559634214">"బగ్ రిపోర్ట్‌‌కు వివరాలను జోడిస్తోంది"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"దయచేసి వేచి ఉండండి..."</string>
-    <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"బగ్ నివేదిక త్వరలో ఫోన్‌లో కనిపిస్తుంది"</string>
-    <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎంచుకోండి"</string>
-    <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"మీ బగ్ నివేదికను షేర్ చేయడానికి నొక్కండి"</string>
-    <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివేదికను భాగస్వామ్యం చేయడానికి ఎంచుకోండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
+    <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"బగ్ రిపోర్ట్‌ త్వరలో ఫోన్‌లో కనిపిస్తుంది"</string>
+    <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"మీ బగ్ రిపోర్ట్‌ను భాగస్వామ్యం చేయడానికి ఎంచుకోండి"</string>
+    <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"మీ బగ్ రిపోర్ట్‌ను షేర్ చేయడానికి నొక్కండి"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ రిపోర్ట్‌ను భాగస్వామ్యం చేయడానికి ఎంచుకోండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"స్క్రీన్‌షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్‌షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
-    <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ రిపోర్ట్స్‌లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేష‌న్‌ డేటా వంటి) డేటాతో పాటు సిస్టమ్‌కు సంబంధించిన విభిన్న లాగ్ ఫైళ్ల డేటా ఉంటుంది. బగ్ నివేదికలను మీరు విశ్వసించే యాప్‌లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
+    <string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ రిపోర్ట్స్‌లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేష‌న్‌ డేటా వంటి) డేటాతో పాటు సిస్టమ్‌కు సంబంధించిన విభిన్న లాగ్ ఫైళ్ల డేటా ఉంటుంది. బగ్ రిపోర్ట్‌లను మీరు విశ్వసించే యాప్‌లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
     <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"మళ్లీ చూపవద్దు"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ రిపోర్ట్స్"</string>
-    <string name="bugreport_unreadable_text" msgid="586517851044535486">"బగ్ నివేదిక ఫైల్‌ను చదవడం సాధ్యపడలేదు"</string>
-    <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"బగ్ నివేదిక వివరాలను జిప్ ఫైల్‌కు జోడించడం సాధ్యపడలేదు"</string>
+    <string name="bugreport_unreadable_text" msgid="586517851044535486">"బగ్ రిపోర్ట్‌ ఫైల్‌ను చదవడం సాధ్యపడలేదు"</string>
+    <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"బగ్ రిపోర్ట్‌ వివరాలను జిప్ ఫైల్‌కు జోడించడం సాధ్యపడలేదు"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"పేరు లేనివి"</string>
     <string name="bugreport_info_action" msgid="2158204228510576227">"వివరాలు"</string>
     <string name="bugreport_screenshot_action" msgid="8677781721940614995">"స్క్రీన్‌షాట్"</string>
     <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"స్క్రీన్‌షాట్ విజయవంతంగా తీయబడింది."</string>
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"స్క్రీన్‌షాట్‌ను తీయడం సాధ్యపడలేదు."</string>
-    <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> వివరాలు"</string>
+    <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"బగ్ రిపోర్ట్‌ <xliff:g id="ID">#%d</xliff:g> వివరాలు"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ఫైల్ పేరు"</string>
     <string name="bugreport_info_title" msgid="2306030793918239804">"బగ్ శీర్షిక"</string>
     <string name="bugreport_info_description" msgid="5072835127481627722">"బగ్ సారాంశం"</string>
     <string name="save" msgid="4781509040564835759">"సేవ్ చేయి"</string>
-    <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"బగ్ నివేదిక షేర్ చేయండి"</string>
+    <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"బగ్ రిపోర్ట్‌ షేర్ చేయండి"</string>
 </resources>
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index c0d353b..075473a 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -185,7 +185,7 @@
         android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
         android:paddingTop="@dimen/qs_media_enabled_seekbar_vertical_padding"
         android:layout_marginTop="-22dp"
-        android:paddingBottom="0dp"
+        android:paddingBottom="2dp"
         android:splitTrack="false" />
 
     <!-- Song name -->
diff --git a/packages/SystemUI/res/raw/udfps_aod_fp.json b/packages/SystemUI/res/raw/udfps_aod_fp.json
index 3b273ff..51d9058 100644
--- a/packages/SystemUI/res/raw/udfps_aod_fp.json
+++ b/packages/SystemUI/res/raw/udfps_aod_fp.json
@@ -5,7 +5,7 @@
   "op":361,
   "w":46,
   "h":65,
-  "nm":"fingerprint_burn_in_Loop_02",
+  "nm":"fingerprint_burn_in_loop",
   "ddd":0,
   "assets":[
 
@@ -15,368 +15,6 @@
       "ddd":0,
       "ind":2,
       "ty":4,
-      "nm":"Fingerprint_20210701 Outlines 9",
-      "sr":1,
-      "ks":{
-        "o":{
-          "a":0,
-          "k":100,
-          "ix":11
-        },
-        "r":{
-          "a":0,
-          "k":0,
-          "ix":10
-        },
-        "p":{
-          "a":0,
-          "k":[
-            23.091,
-            32.5,
-            0
-          ],
-          "ix":2,
-          "l":2
-        },
-        "a":{
-          "a":0,
-          "k":[
-            19.341,
-            24.25,
-            0
-          ],
-          "ix":1,
-          "l":2
-        },
-        "s":{
-          "a":0,
-          "k":[
-            100,
-            100,
-            100
-          ],
-          "ix":6,
-          "l":2
-        }
-      },
-      "ao":0,
-      "shapes":[
-        {
-          "ty":"gr",
-          "it":[
-            {
-              "ind":0,
-              "ty":"sh",
-              "ix":1,
-              "ks":{
-                "a":0,
-                "k":{
-                  "i":[
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      -1.701,
-                      0.42
-                    ],
-                    [
-                      -1.757,
-                      0
-                    ],
-                    [
-                      -1.577,
-                      -0.381
-                    ],
-                    [
-                      -1.485,
-                      -0.816
-                    ]
-                  ],
-                  "o":[
-                    [
-                      1.455,
-                      -0.799
-                    ],
-                    [
-                      1.608,
-                      -0.397
-                    ],
-                    [
-                      1.719,
-                      0
-                    ],
-                    [
-                      1.739,
-                      0.42
-                    ],
-                    [
-                      0,
-                      0
-                    ]
-                  ],
-                  "v":[
-                    [
-                      -9.818,
-                      1.227
-                    ],
-                    [
-                      -5.064,
-                      -0.618
-                    ],
-                    [
-                      0,
-                      -1.227
-                    ],
-                    [
-                      4.96,
-                      -0.643
-                    ],
-                    [
-                      9.818,
-                      1.227
-                    ]
-                  ],
-                  "c":false
-                },
-                "ix":2
-              },
-              "nm":"Path 1",
-              "mn":"ADBE Vector Shape - Group",
-              "hd":false
-            },
-            {
-              "ty":"st",
-              "c":{
-                "a":0,
-                "k":[
-                  1,
-                  1,
-                  1,
-                  1
-                ],
-                "ix":3
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":4
-              },
-              "w":{
-                "a":0,
-                "k":1.3,
-                "ix":5
-              },
-              "lc":2,
-              "lj":1,
-              "ml":10,
-              "bm":0,
-              "nm":"Stroke 1",
-              "mn":"ADBE Vector Graphic - Stroke",
-              "hd":false
-            },
-            {
-              "ty":"tr",
-              "p":{
-                "a":0,
-                "k":[
-                  19.341,
-                  7.477
-                ],
-                "ix":2
-              },
-              "a":{
-                "a":0,
-                "k":[
-                  0,
-                  0
-                ],
-                "ix":1
-              },
-              "s":{
-                "a":0,
-                "k":[
-                  100,
-                  100
-                ],
-                "ix":3
-              },
-              "r":{
-                "a":0,
-                "k":0,
-                "ix":6
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":7
-              },
-              "sk":{
-                "a":0,
-                "k":0,
-                "ix":4
-              },
-              "sa":{
-                "a":0,
-                "k":0,
-                "ix":5
-              },
-              "nm":"Transform"
-            }
-          ],
-          "nm":"Top",
-          "np":2,
-          "cix":2,
-          "bm":0,
-          "ix":1,
-          "mn":"ADBE Vector Group",
-          "hd":false
-        },
-        {
-          "ty":"tm",
-          "s":{
-            "a":0,
-            "k":0,
-            "ix":1
-          },
-          "e":{
-            "a":0,
-            "k":17,
-            "ix":2
-          },
-          "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  246
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  1326
-                ]
-              }
-            ],
-            "ix":3
-          },
-          "m":1,
-          "ix":2,
-          "nm":"Trim Paths 1",
-          "mn":"ADBE Vector Filter - Trim",
-          "hd":false
-        },
-        {
-          "ty":"gr",
-          "it":[
-            {
-              "ty":"tm",
-              "s":{
-                "a":0,
-                "k":0,
-                "ix":1
-              },
-              "e":{
-                "a":0,
-                "k":17,
-                "ix":2
-              },
-              "o":{
-                "a":0,
-                "k":0,
-                "ix":3
-              },
-              "m":1,
-              "ix":1,
-              "nm":"Trim Paths 1",
-              "mn":"ADBE Vector Filter - Trim",
-              "hd":false
-            },
-            {
-              "ty":"tr",
-              "p":{
-                "a":0,
-                "k":[
-                  0,
-                  0
-                ],
-                "ix":2
-              },
-              "a":{
-                "a":0,
-                "k":[
-                  0,
-                  0
-                ],
-                "ix":1
-              },
-              "s":{
-                "a":0,
-                "k":[
-                  100,
-                  100
-                ],
-                "ix":3
-              },
-              "r":{
-                "a":0,
-                "k":0,
-                "ix":6
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":7
-              },
-              "sk":{
-                "a":0,
-                "k":0,
-                "ix":4
-              },
-              "sa":{
-                "a":0,
-                "k":0,
-                "ix":5
-              },
-              "nm":"Transform"
-            }
-          ],
-          "nm":"Group 1",
-          "np":1,
-          "cix":2,
-          "bm":0,
-          "ix":3,
-          "mn":"ADBE Vector Group",
-          "hd":false
-        }
-      ],
-      "ip":0,
-      "op":600,
-      "st":0,
-      "bm":0
-    },
-    {
-      "ddd":0,
-      "ind":3,
-      "ty":4,
       "nm":"Fingerprint_20210701 Outlines 8",
       "sr":1,
       "ks":{
@@ -533,6 +171,55 @@
               "lj":1,
               "ml":10,
               "bm":0,
+              "d":[
+                {
+                  "n":"d",
+                  "nm":"dash",
+                  "v":{
+                    "a":0,
+                    "k":3,
+                    "ix":1
+                  }
+                },
+                {
+                  "n":"o",
+                  "nm":"offset",
+                  "v":{
+                    "a":1,
+                    "k":[
+                      {
+                        "i":{
+                          "x":[
+                            0.833
+                          ],
+                          "y":[
+                            0.833
+                          ]
+                        },
+                        "o":{
+                          "x":[
+                            0.167
+                          ],
+                          "y":[
+                            0.167
+                          ]
+                        },
+                        "t":0,
+                        "s":[
+                          0
+                        ]
+                      },
+                      {
+                        "t":360,
+                        "s":[
+                          -6
+                        ]
+                      }
+                    ],
+                    "ix":7
+                  }
+                }
+              ],
               "nm":"Stroke 1",
               "mn":"ADBE Vector Graphic - Stroke",
               "hd":false
@@ -603,41 +290,12 @@
           },
           "e":{
             "a":0,
-            "k":54,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  0
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  1080
-                ]
-              }
-            ],
+            "a":0,
+            "k":0,
             "ix":3
           },
           "m":1,
@@ -645,257 +303,6 @@
           "nm":"Trim Paths 1",
           "mn":"ADBE Vector Filter - Trim",
           "hd":false
-        }
-      ],
-      "ip":0,
-      "op":600,
-      "st":0,
-      "bm":0
-    },
-    {
-      "ddd":0,
-      "ind":4,
-      "ty":4,
-      "nm":"Fingerprint_20210701 Outlines 7",
-      "sr":1,
-      "ks":{
-        "o":{
-          "a":0,
-          "k":100,
-          "ix":11
-        },
-        "r":{
-          "a":0,
-          "k":0,
-          "ix":10
-        },
-        "p":{
-          "a":0,
-          "k":[
-            23.091,
-            32.5,
-            0
-          ],
-          "ix":2,
-          "l":2
-        },
-        "a":{
-          "a":0,
-          "k":[
-            19.341,
-            24.25,
-            0
-          ],
-          "ix":1,
-          "l":2
-        },
-        "s":{
-          "a":0,
-          "k":[
-            100,
-            100,
-            100
-          ],
-          "ix":6,
-          "l":2
-        }
-      },
-      "ao":0,
-      "shapes":[
-        {
-          "ty":"gr",
-          "it":[
-            {
-              "ind":0,
-              "ty":"sh",
-              "ix":1,
-              "ks":{
-                "a":0,
-                "k":{
-                  "i":[
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      -2.446,
-                      1.161
-                    ],
-                    [
-                      -1.168,
-                      0.275
-                    ],
-                    [
-                      -1.439,
-                      0
-                    ],
-                    [
-                      -1.301,
-                      -0.304
-                    ],
-                    [
-                      -1.225,
-                      -0.66
-                    ],
-                    [
-                      -1.11,
-                      -1.844
-                    ]
-                  ],
-                  "o":[
-                    [
-                      1.23,
-                      -2.044
-                    ],
-                    [
-                      1.024,
-                      -0.486
-                    ],
-                    [
-                      1.312,
-                      -0.31
-                    ],
-                    [
-                      1.425,
-                      0
-                    ],
-                    [
-                      1.454,
-                      0.34
-                    ],
-                    [
-                      2.122,
-                      1.143
-                    ],
-                    [
-                      0,
-                      0
-                    ]
-                  ],
-                  "v":[
-                    [
-                      -13.091,
-                      3.273
-                    ],
-                    [
-                      -7.438,
-                      -1.646
-                    ],
-                    [
-                      -4.14,
-                      -2.797
-                    ],
-                    [
-                      0,
-                      -3.273
-                    ],
-                    [
-                      4.104,
-                      -2.805
-                    ],
-                    [
-                      8.141,
-                      -1.29
-                    ],
-                    [
-                      13.091,
-                      3.273
-                    ]
-                  ],
-                  "c":false
-                },
-                "ix":2
-              },
-              "nm":"Path 1",
-              "mn":"ADBE Vector Shape - Group",
-              "hd":false
-            },
-            {
-              "ty":"st",
-              "c":{
-                "a":0,
-                "k":[
-                  1,
-                  1,
-                  1,
-                  1
-                ],
-                "ix":3
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":4
-              },
-              "w":{
-                "a":0,
-                "k":1.3,
-                "ix":5
-              },
-              "lc":2,
-              "lj":1,
-              "ml":10,
-              "bm":0,
-              "nm":"Stroke 1",
-              "mn":"ADBE Vector Graphic - Stroke",
-              "hd":false
-            },
-            {
-              "ty":"tr",
-              "p":{
-                "a":0,
-                "k":[
-                  19.341,
-                  16.069
-                ],
-                "ix":2
-              },
-              "a":{
-                "a":0,
-                "k":[
-                  0,
-                  0
-                ],
-                "ix":1
-              },
-              "s":{
-                "a":0,
-                "k":[
-                  100,
-                  100
-                ],
-                "ix":3
-              },
-              "r":{
-                "a":0,
-                "k":0,
-                "ix":6
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":7
-              },
-              "sk":{
-                "a":0,
-                "k":0,
-                "ix":4
-              },
-              "sa":{
-                "a":0,
-                "k":0,
-                "ix":5
-              },
-              "nm":"Transform"
-            }
-          ],
-          "nm":"Mid Top",
-          "np":2,
-          "cix":2,
-          "bm":0,
-          "ix":1,
-          "mn":"ADBE Vector Group",
-          "hd":false
         },
         {
           "ty":"tm",
@@ -906,46 +313,17 @@
           },
           "e":{
             "a":0,
-            "k":38.2,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  170
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  890
-                ]
-              }
-            ],
+            "a":0,
+            "k":0,
             "ix":3
           },
           "m":1,
-          "ix":2,
-          "nm":"Trim Paths 1",
+          "ix":3,
+          "nm":"Trim Paths 2",
           "mn":"ADBE Vector Filter - Trim",
           "hd":false
         }
@@ -957,7 +335,7 @@
     },
     {
       "ddd":0,
-      "ind":5,
+      "ind":3,
       "ty":4,
       "nm":"Fingerprint_20210701 Outlines 6",
       "sr":1,
@@ -1139,6 +517,55 @@
               "lj":1,
               "ml":10,
               "bm":0,
+              "d":[
+                {
+                  "n":"d",
+                  "nm":"dash",
+                  "v":{
+                    "a":0,
+                    "k":3,
+                    "ix":1
+                  }
+                },
+                {
+                  "n":"o",
+                  "nm":"offset",
+                  "v":{
+                    "a":1,
+                    "k":[
+                      {
+                        "i":{
+                          "x":[
+                            0.833
+                          ],
+                          "y":[
+                            0.833
+                          ]
+                        },
+                        "o":{
+                          "x":[
+                            0.167
+                          ],
+                          "y":[
+                            0.167
+                          ]
+                        },
+                        "t":0,
+                        "s":[
+                          0
+                        ]
+                      },
+                      {
+                        "t":360,
+                        "s":[
+                          -6
+                        ]
+                      }
+                    ],
+                    "ix":7
+                  }
+                }
+              ],
               "nm":"Stroke 1",
               "mn":"ADBE Vector Graphic - Stroke",
               "hd":false
@@ -1209,41 +636,12 @@
           },
           "e":{
             "a":0,
-            "k":34.2,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  0
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  720
-                ]
-              }
-            ],
+            "a":0,
+            "k":0,
             "ix":3
           },
           "m":1,
@@ -1260,7 +658,7 @@
     },
     {
       "ddd":0,
-      "ind":6,
+      "ind":4,
       "ty":4,
       "nm":"Fingerprint_20210701 Outlines 5",
       "sr":1,
@@ -1514,6 +912,55 @@
               "lj":1,
               "ml":10,
               "bm":0,
+              "d":[
+                {
+                  "n":"d",
+                  "nm":"dash",
+                  "v":{
+                    "a":0,
+                    "k":3,
+                    "ix":1
+                  }
+                },
+                {
+                  "n":"o",
+                  "nm":"offset",
+                  "v":{
+                    "a":1,
+                    "k":[
+                      {
+                        "i":{
+                          "x":[
+                            0.833
+                          ],
+                          "y":[
+                            0.833
+                          ]
+                        },
+                        "o":{
+                          "x":[
+                            0.167
+                          ],
+                          "y":[
+                            0.167
+                          ]
+                        },
+                        "t":0,
+                        "s":[
+                          0
+                        ]
+                      },
+                      {
+                        "t":360,
+                        "s":[
+                          -6
+                        ]
+                      }
+                    ],
+                    "ix":7
+                  }
+                }
+              ],
               "nm":"Stroke 1",
               "mn":"ADBE Vector Graphic - Stroke",
               "hd":false
@@ -1584,416 +1031,12 @@
           },
           "e":{
             "a":0,
-            "k":35,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  -159
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  201
-                ]
-              }
-            ],
-            "ix":3
-          },
-          "m":1,
-          "ix":2,
-          "nm":"Trim Paths 1",
-          "mn":"ADBE Vector Filter - Trim",
-          "hd":false
-        }
-      ],
-      "ip":0,
-      "op":600,
-      "st":0,
-      "bm":0
-    },
-    {
-      "ddd":0,
-      "ind":7,
-      "ty":4,
-      "nm":"Fingerprint_20210701 Outlines 4",
-      "sr":1,
-      "ks":{
-        "o":{
-          "a":0,
-          "k":100,
-          "ix":11
-        },
-        "r":{
-          "a":0,
-          "k":0,
-          "ix":10
-        },
-        "p":{
-          "a":0,
-          "k":[
-            23.091,
-            32.5,
-            0
-          ],
-          "ix":2,
-          "l":2
-        },
-        "a":{
-          "a":0,
-          "k":[
-            19.341,
-            24.25,
-            0
-          ],
-          "ix":1,
-          "l":2
-        },
-        "s":{
-          "a":0,
-          "k":[
-            100,
-            100,
-            100
-          ],
-          "ix":6,
-          "l":2
-        }
-      },
-      "ao":0,
-      "shapes":[
-        {
-          "ty":"gr",
-          "it":[
-            {
-              "ind":0,
-              "ty":"sh",
-              "ix":1,
-              "ks":{
-                "a":0,
-                "k":{
-                  "i":[
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      -6.53,
-                      0
-                    ],
-                    [
-                      0,
-                      -5.793
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      2.159,
-                      0
-                    ],
-                    [
-                      0.59,
-                      1.489
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      1.587,
-                      0
-                    ],
-                    [
-                      0,
-                      -2.16
-                    ],
-                    [
-                      -0.81,
-                      -1.363
-                    ],
-                    [
-                      -0.844,
-                      -0.674
-                    ],
-                    [
-                      0,
-                      0
-                    ]
-                  ],
-                  "o":[
-                    [
-                      -0.753,
-                      -2.095
-                    ],
-                    [
-                      0,
-                      -5.793
-                    ],
-                    [
-                      6.529,
-                      0
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      0,
-                      2.16
-                    ],
-                    [
-                      -1.604,
-                      0
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      -0.589,
-                      -1.489
-                    ],
-                    [
-                      -2.161,
-                      0
-                    ],
-                    [
-                      0,
-                      1.62
-                    ],
-                    [
-                      0.54,
-                      0.909
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      0,
-                      0
-                    ]
-                  ],
-                  "v":[
-                    [
-                      -10.702,
-                      5.728
-                    ],
-                    [
-                      -11.454,
-                      1.506
-                    ],
-                    [
-                      0.001,
-                      -9
-                    ],
-                    [
-                      11.454,
-                      1.506
-                    ],
-                    [
-                      11.454,
-                      1.817
-                    ],
-                    [
-                      7.544,
-                      5.728
-                    ],
-                    [
-                      3.926,
-                      3.273
-                    ],
-                    [
-                      2.618,
-                      0
-                    ],
-                    [
-                      -0.997,
-                      -2.454
-                    ],
-                    [
-                      -4.91,
-                      1.457
-                    ],
-                    [
-                      -3.657,
-                      6.014
-                    ],
-                    [
-                      -1.57,
-                      8.412
-                    ],
-                    [
-                      -0.818,
-                      9
-                    ]
-                  ],
-                  "c":false
-                },
-                "ix":2
-              },
-              "nm":"Path 1",
-              "mn":"ADBE Vector Shape - Group",
-              "hd":false
-            },
-            {
-              "ty":"st",
-              "c":{
-                "a":0,
-                "k":[
-                  1,
-                  1,
-                  1,
-                  1
-                ],
-                "ix":3
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":4
-              },
-              "w":{
-                "a":0,
-                "k":1.3,
-                "ix":5
-              },
-              "lc":2,
-              "lj":1,
-              "ml":10,
-              "bm":0,
-              "nm":"Stroke 1",
-              "mn":"ADBE Vector Graphic - Stroke",
-              "hd":false
-            },
-            {
-              "ty":"tr",
-              "p":{
-                "a":0,
-                "k":[
-                  19.341,
-                  28.341
-                ],
-                "ix":2
-              },
-              "a":{
-                "a":0,
-                "k":[
-                  0,
-                  0
-                ],
-                "ix":1
-              },
-              "s":{
-                "a":0,
-                "k":[
-                  100,
-                  100
-                ],
-                "ix":3
-              },
-              "r":{
-                "a":0,
-                "k":0,
-                "ix":6
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":7
-              },
-              "sk":{
-                "a":0,
-                "k":0,
-                "ix":4
-              },
-              "sa":{
-                "a":0,
-                "k":0,
-                "ix":5
-              },
-              "nm":"Transform"
-            }
-          ],
-          "nm":"Inside to dot ",
-          "np":2,
-          "cix":2,
-          "bm":0,
-          "ix":1,
-          "mn":"ADBE Vector Group",
-          "hd":false
-        },
-        {
-          "ty":"tm",
-          "s":{
             "a":0,
             "k":0,
-            "ix":1
-          },
-          "e":{
-            "a":0,
-            "k":9,
-            "ix":2
-          },
-          "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  135
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  495
-                ]
-              }
-            ],
             "ix":3
           },
           "m":1,
@@ -2010,382 +1053,7 @@
     },
     {
       "ddd":0,
-      "ind":8,
-      "ty":4,
-      "nm":"Fingerprint_20210701 Outlines 3",
-      "sr":1,
-      "ks":{
-        "o":{
-          "a":0,
-          "k":100,
-          "ix":11
-        },
-        "r":{
-          "a":0,
-          "k":0,
-          "ix":10
-        },
-        "p":{
-          "a":0,
-          "k":[
-            23.091,
-            32.5,
-            0
-          ],
-          "ix":2,
-          "l":2
-        },
-        "a":{
-          "a":0,
-          "k":[
-            19.341,
-            24.25,
-            0
-          ],
-          "ix":1,
-          "l":2
-        },
-        "s":{
-          "a":0,
-          "k":[
-            100,
-            100,
-            100
-          ],
-          "ix":6,
-          "l":2
-        }
-      },
-      "ao":0,
-      "shapes":[
-        {
-          "ty":"gr",
-          "it":[
-            {
-              "ind":0,
-              "ty":"sh",
-              "ix":1,
-              "ks":{
-                "a":0,
-                "k":{
-                  "i":[
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      -6.53,
-                      0
-                    ],
-                    [
-                      0,
-                      -5.793
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      2.159,
-                      0
-                    ],
-                    [
-                      0.59,
-                      1.489
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      1.587,
-                      0
-                    ],
-                    [
-                      0,
-                      -2.16
-                    ],
-                    [
-                      -0.81,
-                      -1.363
-                    ],
-                    [
-                      -0.844,
-                      -0.674
-                    ],
-                    [
-                      0,
-                      0
-                    ]
-                  ],
-                  "o":[
-                    [
-                      -0.753,
-                      -2.095
-                    ],
-                    [
-                      0,
-                      -5.793
-                    ],
-                    [
-                      6.529,
-                      0
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      0,
-                      2.16
-                    ],
-                    [
-                      -1.604,
-                      0
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      -0.589,
-                      -1.489
-                    ],
-                    [
-                      -2.161,
-                      0
-                    ],
-                    [
-                      0,
-                      1.62
-                    ],
-                    [
-                      0.54,
-                      0.909
-                    ],
-                    [
-                      0,
-                      0
-                    ],
-                    [
-                      0,
-                      0
-                    ]
-                  ],
-                  "v":[
-                    [
-                      -10.702,
-                      5.728
-                    ],
-                    [
-                      -11.454,
-                      1.506
-                    ],
-                    [
-                      0.001,
-                      -9
-                    ],
-                    [
-                      11.454,
-                      1.506
-                    ],
-                    [
-                      11.454,
-                      1.817
-                    ],
-                    [
-                      7.544,
-                      5.728
-                    ],
-                    [
-                      3.926,
-                      3.273
-                    ],
-                    [
-                      2.618,
-                      0
-                    ],
-                    [
-                      -0.997,
-                      -2.454
-                    ],
-                    [
-                      -4.91,
-                      1.457
-                    ],
-                    [
-                      -3.657,
-                      6.014
-                    ],
-                    [
-                      -1.57,
-                      8.412
-                    ],
-                    [
-                      -0.818,
-                      9
-                    ]
-                  ],
-                  "c":false
-                },
-                "ix":2
-              },
-              "nm":"Path 1",
-              "mn":"ADBE Vector Shape - Group",
-              "hd":false
-            },
-            {
-              "ty":"st",
-              "c":{
-                "a":0,
-                "k":[
-                  1,
-                  1,
-                  1,
-                  1
-                ],
-                "ix":3
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":4
-              },
-              "w":{
-                "a":0,
-                "k":1.3,
-                "ix":5
-              },
-              "lc":2,
-              "lj":1,
-              "ml":10,
-              "bm":0,
-              "nm":"Stroke 1",
-              "mn":"ADBE Vector Graphic - Stroke",
-              "hd":false
-            },
-            {
-              "ty":"tr",
-              "p":{
-                "a":0,
-                "k":[
-                  19.341,
-                  28.341
-                ],
-                "ix":2
-              },
-              "a":{
-                "a":0,
-                "k":[
-                  0,
-                  0
-                ],
-                "ix":1
-              },
-              "s":{
-                "a":0,
-                "k":[
-                  100,
-                  100
-                ],
-                "ix":3
-              },
-              "r":{
-                "a":0,
-                "k":0,
-                "ix":6
-              },
-              "o":{
-                "a":0,
-                "k":100,
-                "ix":7
-              },
-              "sk":{
-                "a":0,
-                "k":0,
-                "ix":4
-              },
-              "sa":{
-                "a":0,
-                "k":0,
-                "ix":5
-              },
-              "nm":"Transform"
-            }
-          ],
-          "nm":"Inside to dot ",
-          "np":2,
-          "cix":2,
-          "bm":0,
-          "ix":1,
-          "mn":"ADBE Vector Group",
-          "hd":false
-        },
-        {
-          "ty":"tm",
-          "s":{
-            "a":0,
-            "k":0,
-            "ix":1
-          },
-          "e":{
-            "a":0,
-            "k":30,
-            "ix":2
-          },
-          "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  0
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  360
-                ]
-              }
-            ],
-            "ix":3
-          },
-          "m":1,
-          "ix":2,
-          "nm":"Trim Paths 1",
-          "mn":"ADBE Vector Filter - Trim",
-          "hd":false
-        }
-      ],
-      "ip":0,
-      "op":600,
-      "st":0,
-      "bm":0
-    },
-    {
-      "ddd":0,
-      "ind":9,
+      "ind":5,
       "ty":4,
       "nm":"Fingerprint_20210701 Outlines",
       "sr":1,
@@ -2567,6 +1235,55 @@
               "lj":1,
               "ml":10,
               "bm":0,
+              "d":[
+                {
+                  "n":"d",
+                  "nm":"dash",
+                  "v":{
+                    "a":0,
+                    "k":2.5,
+                    "ix":1
+                  }
+                },
+                {
+                  "n":"o",
+                  "nm":"offset",
+                  "v":{
+                    "a":1,
+                    "k":[
+                      {
+                        "i":{
+                          "x":[
+                            0.833
+                          ],
+                          "y":[
+                            0.833
+                          ]
+                        },
+                        "o":{
+                          "x":[
+                            0.167
+                          ],
+                          "y":[
+                            0.167
+                          ]
+                        },
+                        "t":0,
+                        "s":[
+                          0
+                        ]
+                      },
+                      {
+                        "t":360,
+                        "s":[
+                          -5
+                        ]
+                      }
+                    ],
+                    "ix":7
+                  }
+                }
+              ],
               "nm":"Stroke 1",
               "mn":"ADBE Vector Graphic - Stroke",
               "hd":false
@@ -2637,41 +1354,12 @@
           },
           "e":{
             "a":0,
-            "k":69,
+            "k":100,
             "ix":2
           },
           "o":{
-            "a":1,
-            "k":[
-              {
-                "i":{
-                  "x":[
-                    0.833
-                  ],
-                  "y":[
-                    0.833
-                  ]
-                },
-                "o":{
-                  "x":[
-                    0.167
-                  ],
-                  "y":[
-                    0.167
-                  ]
-                },
-                "t":0,
-                "s":[
-                  0
-                ]
-              },
-              {
-                "t":360,
-                "s":[
-                  720
-                ]
-              }
-            ],
+            "a":0,
+            "k":0,
             "ix":3
           },
           "m":1,
@@ -2699,4 +1387,4 @@
       "dr":0
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 4f4892c..b6162a8 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -58,7 +58,7 @@
     <string name="always_use_device" msgid="210535878779644679">"Ireki <xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_DEVICE">%2$s</xliff:g> konektatzen den guztietan"</string>
     <string name="always_use_accessory" msgid="1977225429341838444">"Ireki <xliff:g id="APPLICATION">%1$s</xliff:g> <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> konektatzen den guztietan"</string>
     <string name="usb_debugging_title" msgid="8274884945238642726">"USB bidezko arazketa onartu?"</string>
-    <string name="usb_debugging_message" msgid="5794616114463921773">"Ordenagailuaren RSA gakoaren erreferentzia-gako digitala hau da:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_message" msgid="5794616114463921773">"Ordenagailuaren RSA gakoaren aztarna digitala hau da:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
     <string name="usb_debugging_always" msgid="4003121804294739548">"Eman beti ordenagailu honetatik arazteko baimena"</string>
     <string name="usb_debugging_allow" msgid="1722643858015321328">"Eman baimena"</string>
     <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Ez da onartzen USB bidezko arazketa"</string>
@@ -577,7 +577,7 @@
     <string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
     <string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Ireki kredentzial fidagarriak"</string>
     <string name="monitoring_description_network_logging" msgid="577305979174002252">"Administratzaileak sarearen erregistroak aktibatu ditu; horrela, zure gailuko trafikoa gainbegira dezake.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan."</string>
-    <string name="monitoring_description_vpn" msgid="1685428000684586870">"Aplikazio bati VPN konexio bat konfiguratzeko baimena eman diozu.\n\nAplikazio horrek gailuko eta sareko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
+    <string name="monitoring_description_vpn" msgid="1685428000684586870">"Aplikazio bati VPN bidezko konexio bat konfiguratzeko baimena eman diozu.\n\nAplikazio horrek gailuko eta sareko jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
     <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> erakundeak kudeatzen du zure laneko profila.\n\nAdministratzaileak sareko jarduerak kontrola diezazkizuke, besteak beste, posta elektronikoa, aplikazioak eta webguneak.\n\nInformazio gehiago lortzeko, jarri administratzailearekin harremanetan.\n\nHorrez gain, VPN batera zaude konektatuta, eta hark ere kontrola ditzake zure sareko jarduerak."</string>
     <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Zure gurasoak kudeatzen du gailua. Zure gurasoak gailuko informazioa ikusi eta kudea dezake; besteak beste, zer aplikazio erabiltzen dituzun, zure kokapena zein den eta pantaila aurrean zenbat eta noiz egoten zaren."</string>
     <string name="legacy_vpn_name" msgid="4174223520162559145">"VPN konexioa"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index cee7019..1202a746 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -148,7 +148,7 @@
     <string name="voice_assist_label" msgid="3725967093735929020">"व्हॉइस सहाय्य उघडा"</string>
     <string name="camera_label" msgid="8253821920931143699">"कॅमेरा उघडा"</string>
     <string name="cancel" msgid="1089011503403416730">"रद्द करा"</string>
-    <string name="biometric_dialog_confirm" msgid="2005978443007344895">"खात्री करा"</string>
+    <string name="biometric_dialog_confirm" msgid="2005978443007344895">"कंफर्म करा"</string>
     <string name="biometric_dialog_try_again" msgid="8575345628117768844">"पुन्हा प्रयत्न करा"</string>
     <string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"ऑथेंटिकेशन रद्द करण्यासाठी टॅप करा"</string>
     <string name="biometric_dialog_face_icon_description_idle" msgid="4351777022315116816">"कृपया पुन्हा प्रयत्न करा"</string>
diff --git a/packages/SystemUI/res/values-te-ldrtl/strings.xml b/packages/SystemUI/res/values-te-ldrtl/strings.xml
index 1c1b562..94bdbcf 100644
--- a/packages/SystemUI/res/values-te-ldrtl/strings.xml
+++ b/packages/SystemUI/res/values-te-ldrtl/strings.xml
@@ -19,5 +19,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recents_quick_scrub_onboarding" msgid="2452671841151577157">"యాప్‌లను శీఘ్రంగా స్విచ్ చేయడానికి ఎడమ వైపుకు లాగండి"</string>
+    <string name="recents_quick_scrub_onboarding" msgid="2452671841151577157">"యాప్‌లను శీఘ్రంగా స్విచ్ చేయడానికి ఎడమ వైపునకు లాగండి"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 7ad382e..45236a7 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -319,10 +319,10 @@
     <string name="notification_summary_message_format" msgid="5158219088501909966">"<xliff:g id="CONTACT_NAME">%1$s</xliff:g>: <xliff:g id="MESSAGE_CONTENT">%2$s</xliff:g>"</string>
     <string name="status_bar_notification_inspect_item_title" msgid="6818779631806163080">"నోటిఫికేషన్ సెట్టింగ్‌లు"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5050006438806013903">"<xliff:g id="APP_NAME">%s</xliff:g> సెట్టింగ్‌లు"</string>
-    <string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"స్క్రీన్ స్వయంచాలకంగా తిప్పబడుతుంది."</string>
+    <string name="accessibility_rotation_lock_off" msgid="3880436123632448930">"స్క్రీన్ ఆటోమేటిక్‌గా తిప్పబడుతుంది."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="936972553861524360">"స్క్రీన్ ల్యాండ్‌స్కేప్ దృగ్విన్యాసంలో లాక్ చేయబడుతుంది."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="2356633398683813837">"స్క్రీన్ పోర్ట్రెయిట్ దృగ్విన్యాసంలో లాక్ చేయబడుతుంది."</string>
-    <string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"స్క్రీన్ ఇప్పుడు స్వయంచాలకంగా తిరుగుతుంది."</string>
+    <string name="accessibility_rotation_lock_off_changed" msgid="5772498370935088261">"స్క్రీన్ ఇప్పుడు ఆటోమేటిక్‌గా తిరుగుతుంది."</string>
     <string name="accessibility_rotation_lock_on_landscape_changed" msgid="5785739044300729592">"స్క్రీన్ ఇప్పుడు ల్యాండ్‌స్కేప్ దృగ్విన్యాసంలో లాక్ చేయబడింది."</string>
     <string name="accessibility_rotation_lock_on_portrait_changed" msgid="5580170829728987989">"స్క్రీన్ ఇప్పుడు పోర్ట్రెయిట్ దృగ్విన్యాసంలో లాక్ చేయబడింది."</string>
     <string name="dessert_case" msgid="9104973640704357717">"డెజర్ట్ కేస్"</string>
@@ -941,7 +941,7 @@
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
     <string name="high_temp_title" msgid="2218333576838496100">"ఫోన్ వేడెక్కుతోంది"</string>
     <string name="high_temp_notif_message" msgid="1277346543068257549">"ఫోన్‌ను చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
-    <string name="high_temp_dialog_message" msgid="3793606072661253968">"మీ ఫోన్ స్వయంచాలకంగా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్‌ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
+    <string name="high_temp_dialog_message" msgid="3793606072661253968">"మీ ఫోన్ ఆటోమేటిక్‌గా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్‌ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
     <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
     <string name="high_temp_alarm_title" msgid="2359958549570161495">"ప్లగ్ నుండి ఛార్జర్‌ తీసివేయండి"</string>
     <string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ఈ పరికరాన్ని ఛార్జ్ చేయడంలో సమస్య ఉంది. పవర్ అడాప్టర్‌ను ప్లగ్ నుండి తీసివేసి, కేబుల్ ఏమైనా వేడిగా అయితే తగిన జాగ్రత్తలు తీసుకోండి."</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 307da67..e701ec7 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1296,7 +1296,7 @@
     <!-- Size of media cards in the QSPanel carousel -->
     <dimen name="qs_media_padding">16dp</dimen>
     <dimen name="qs_media_album_size_small">72dp</dimen>
-    <dimen name="qs_media_album_size">92dp</dimen>
+    <dimen name="qs_media_album_size">84dp</dimen>
     <dimen name="qs_media_album_radius">14dp</dimen>
     <dimen name="qs_media_album_device_padding">26dp</dimen>
     <dimen name="qs_media_info_margin">12dp</dimen>
@@ -1313,13 +1313,14 @@
     <dimen name="qs_footer_horizontal_margin">22dp</dimen>
     <dimen name="qs_media_disabled_seekbar_height">1dp</dimen>
     <dimen name="qs_media_enabled_seekbar_height">2dp</dimen>
-    <dimen name="qs_media_enabled_seekbar_vertical_padding">31dp</dimen>
-    <dimen name="qs_media_disabled_seekbar_vertical_padding">32dp</dimen>
+    <dimen name="qs_media_enabled_seekbar_vertical_padding">28dp</dimen>
+    <dimen name="qs_media_disabled_seekbar_vertical_padding">29dp</dimen>
 
     <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
     <dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
-    <dimen name="qs_aa_media_rec_album_size_expanded">80dp</dimen>
+    <dimen name="qs_aa_media_rec_album_size_expanded">76dp</dimen>
     <dimen name="qs_aa_media_rec_album_margin">8dp</dimen>
+    <dimen name="qs_aa_media_rec_album_margin_vert">4dp</dimen>
     <dimen name="qq_aa_media_rec_header_text_size">16sp</dimen>
 
     <!-- Window magnification -->
diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml
index 9d706c5..0e284e6 100644
--- a/packages/SystemUI/res/xml/media_expanded.xml
+++ b/packages/SystemUI/res/xml/media_expanded.xml
@@ -93,7 +93,7 @@
         android:layout_marginEnd="@dimen/qs_media_padding"
         android:layout_marginBottom="@dimen/qs_media_info_margin"
         app:layout_constrainedWidth="true"
-        android:layout_marginTop="@dimen/qs_media_info_spacing"
+        android:layout_marginTop="1dp"
         app:layout_constraintTop_toBottomOf="@id/header_title"
         app:layout_constraintStart_toStartOf="@id/header_title"
         app:layout_constraintEnd_toEndOf="parent"
@@ -104,7 +104,8 @@
         android:id="@+id/media_progress_bar"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        app:layout_constraintTop_toBottomOf="@id/header_artist"
+        android:layout_marginTop="34dp"
+        app:layout_constraintTop_toBottomOf="@id/center_horizontal_guideline"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         />
@@ -124,7 +125,6 @@
         android:id="@+id/action0"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -139,7 +139,6 @@
         android:id="@+id/action1"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -153,7 +152,6 @@
         android:id="@+id/action2"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -167,7 +165,6 @@
         android:id="@+id/action3"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_action_spacing"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
@@ -181,7 +178,6 @@
         android:id="@+id/action4"
         android:layout_width="48dp"
         android:layout_height="48dp"
-        android:layout_marginTop="@dimen/qs_media_action_margin"
         android:layout_marginStart="@dimen/qs_media_action_spacing"
         android:layout_marginEnd="@dimen/qs_media_padding"
         android:layout_marginBottom="@dimen/qs_media_action_margin"
diff --git a/packages/SystemUI/res/xml/media_recommendation_expanded.xml b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
index d8e132c..8a3d5ca 100644
--- a/packages/SystemUI/res/xml/media_recommendation_expanded.xml
+++ b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
@@ -43,7 +43,7 @@
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
         android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
@@ -61,7 +61,7 @@
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
         android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
@@ -79,7 +79,7 @@
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
         android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
         app:layout_constraintStart_toEndOf="@id/media_cover2_container"
@@ -95,7 +95,7 @@
         android:layout_width="0dp"
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
-        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginBottom="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
         app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
@@ -113,7 +113,7 @@
         android:layout_width="0dp"
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
-        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginBottom="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
         app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
@@ -131,7 +131,7 @@
         android:layout_width="0dp"
         android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
         app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
-        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin"
+        android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
         android:layout_marginBottom="@dimen/qs_media_padding"
         app:layout_constraintTop_toBottomOf="@id/media_horizontal_center_guideline"
         app:layout_constraintBottom_toBottomOf="parent"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 23a365a..68905f7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -216,7 +216,7 @@
             activityType = ACTIVITY_TYPE_UNDEFINED;
         }
         taskInfo = change.getTaskInfo();
-        allowEnterPip = false; /* always false in shell-transition case */
+        allowEnterPip = change.getAllowEnterPip();
         mStartLeash = null;
         rotationChange = change.getEndRotation() - change.getStartRotation();
         windowType = INVALID_WINDOW_TYPE;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
deleted file mode 100644
index 0785cc3..0000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.android.keyguard
-
-import android.annotation.CurrentTimeMillisLong
-
-/**
- * Data class for tracking information associated with [KeyguardUpdateMonitor.shouldListenForFace]
- * method calls.
- */
-data class KeyguardFaceListenModel(
-    @CurrentTimeMillisLong val timeMillis: Long,
-    val userId: Int,
-    val isListeningForFace: Boolean,
-    val isBouncer: Boolean,
-    val isAuthInterruptActive: Boolean,
-    val isOccludingAppRequestingFaceAuth: Boolean,
-    val isKeyguardAwake: Boolean,
-    val isListeningForFaceAssistant: Boolean,
-    val isSwitchingUser: Boolean,
-    val isFaceDisabled: Boolean,
-    val isBecauseCannotSkipBouncer: Boolean,
-    val isKeyguardGoingAway: Boolean,
-    val isBiometricSettingEnabledForUser: Boolean,
-    val isLockIconPressed: Boolean,
-    val isScanningAllowedByStrongAuth: Boolean,
-    val isPrimaryUser: Boolean,
-    val isSecureCameraLaunched: Boolean,
-    val isFaceAuthenticated: Boolean
-)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
new file mode 100644
index 0000000..9286175
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
@@ -0,0 +1,77 @@
+package com.android.keyguard
+
+import android.annotation.CurrentTimeMillisLong
+import android.hardware.biometrics.BiometricAuthenticator.Modality
+import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
+import android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT
+
+/** Verbose logging for various keyguard listening states. */
+sealed class KeyguardListenModel {
+    /** Timestamp of the state change. */
+    abstract val timeMillis: Long
+    /** Current user */
+    abstract val userId: Int
+    /** If keyguard is listening for the given [modality]. */
+    abstract val listening: Boolean
+    /** Sensor type */
+    @Modality abstract val modality: Int
+}
+
+/**
+ * Verbose debug information associated with [KeyguardUpdateMonitor.shouldListenForFingerprint].
+ */
+data class KeyguardFingerprintListenModel(
+    @CurrentTimeMillisLong override val timeMillis: Long,
+    override val userId: Int,
+    override val listening: Boolean,
+    // keep sorted
+    val biometricEnabledForUser: Boolean,
+    val bouncer: Boolean,
+    val canSkipBouncer: Boolean,
+    val credentialAttempted: Boolean,
+    val deviceInteractive: Boolean,
+    val dreaming: Boolean,
+    val encryptedOrLockdown: Boolean,
+    val fingerprintDisabled: Boolean,
+    val fingerprintLockedOut: Boolean,
+    val goingToSleep: Boolean,
+    val keyguardGoingAway: Boolean,
+    val keyguardIsVisible: Boolean,
+    val keyguardOccluded: Boolean,
+    val occludingAppRequestingFp: Boolean,
+    val primaryUser: Boolean,
+    val shouldListenForFingerprintAssistant: Boolean,
+    val switchingUser: Boolean,
+    val udfps: Boolean,
+    val userDoesNotHaveTrust: Boolean,
+    val userNeedsStrongAuth: Boolean
+) : KeyguardListenModel() {
+    override val modality: Int = TYPE_FACE
+}
+
+/**
+ * Verbose debug information associated with [KeyguardUpdateMonitor.shouldListenForFace].
+ */
+data class KeyguardFaceListenModel(
+    @CurrentTimeMillisLong override val timeMillis: Long,
+    override val userId: Int,
+    override val listening: Boolean,
+    // keep sorted
+    val authInterruptActive: Boolean,
+    val becauseCannotSkipBouncer: Boolean,
+    val biometricSettingEnabledForUser: Boolean,
+    val bouncer: Boolean,
+    val faceAuthenticated: Boolean,
+    val faceDisabled: Boolean,
+    val keyguardAwake: Boolean,
+    val keyguardGoingAway: Boolean,
+    val listeningForFaceAssistant: Boolean,
+    val lockIconPressed: Boolean,
+    val occludingAppRequestingFaceAuth: Boolean,
+    val primaryUser: Boolean,
+    val scanningAllowedByStrongAuth: Boolean,
+    val secureCameraLaunched: Boolean,
+    val switchingUser: Boolean
+) : KeyguardListenModel() {
+    override val modality: Int = TYPE_FINGERPRINT
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt
new file mode 100644
index 0000000..f13a59a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.keyguard
+
+import androidx.annotation.VisibleForTesting
+import java.io.PrintWriter
+import java.text.DateFormat
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+import kotlin.collections.ArrayDeque
+
+private val DEFAULT_FORMATTING = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US)
+
+/** Queue for verbose logging checks for the listening state. */
+class KeyguardListenQueue(
+    val sizePerModality: Int = 20
+) {
+    private val faceQueue = ArrayDeque<KeyguardFaceListenModel>()
+    private val fingerprintQueue = ArrayDeque<KeyguardFingerprintListenModel>()
+
+    @get:VisibleForTesting val models: List<KeyguardListenModel>
+        get() = faceQueue + fingerprintQueue
+
+    /** Push a [model] to the queue (will be logged until the queue exceeds [sizePerModality]). */
+    fun add(model: KeyguardListenModel) {
+        val queue = when (model) {
+            is KeyguardFaceListenModel -> faceQueue.apply { add(model) }
+            is KeyguardFingerprintListenModel -> fingerprintQueue.apply { add(model) }
+        }
+
+        if (queue.size > sizePerModality) {
+            queue.removeFirstOrNull()
+        }
+    }
+
+    /** Print verbose logs via the [writer]. */
+    @JvmOverloads
+    fun print(writer: PrintWriter, dateFormat: DateFormat = DEFAULT_FORMATTING) {
+        val stringify: (KeyguardListenModel) -> String = { model ->
+            "    ${dateFormat.format(Date(model.timeMillis))} $model"
+        }
+
+        writer.println("  Face listen results (last ${faceQueue.size} calls):")
+        for (model in faceQueue) {
+            writer.println(stringify(model))
+        }
+        writer.println("  Fingerprint listen results (last ${fingerprintQueue.size} calls):")
+        for (model in fingerprintQueue) {
+            writer.println(stringify(model))
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index cb5c6c3..0df2d65 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -162,7 +162,9 @@
                     try {
                         Thread.sleep(5000);
                     } catch (InterruptedException ignored) { }
-                    Runtime.getRuntime().gc();
+                    System.gc();
+                    System.runFinalization();
+                    System.gc();
                 });
             } else {
                 SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 6908409..92d1bc4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -118,15 +118,11 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
-import java.text.SimpleDateFormat;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -148,6 +144,7 @@
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
     private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
     private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
+    private static final boolean DEBUG_FINGERPRINT = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_SPEW = false;
     private static final int FINGERPRINT_LOCKOUT_RESET_DELAY_MS = 600;
 
@@ -422,9 +419,8 @@
     @VisibleForTesting
     SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
 
-    // Keep track of recent calls to shouldListenForFace() for debugging.
-    private static final int FACE_LISTEN_CALLS_QUEUE_SIZE = 20;
-    private ArrayDeque<KeyguardFaceListenModel> mFaceListenModels;
+    // Keep track of recent calls to shouldListenFor*() for debugging.
+    private final KeyguardListenQueue mListenModels = new KeyguardListenQueue();
 
     private static int sCurrentUser;
     private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;
@@ -2229,37 +2225,75 @@
 
     @VisibleForTesting
     protected boolean shouldListenForFingerprint(boolean isUdfps) {
-        final boolean userDoesNotHaveTrust = !getUserHasTrust(getCurrentUser());
+        final int user = getCurrentUser();
+        final boolean userDoesNotHaveTrust = !getUserHasTrust(user);
+        final boolean shouldListenForFingerprintAssistant = shouldListenForFingerprintAssistant();
         final boolean shouldListenKeyguardState =
                 mKeyguardIsVisible
                         || !mDeviceInteractive
                         || (mBouncer && !mKeyguardGoingAway)
                         || mGoingToSleep
-                        || shouldListenForFingerprintAssistant()
+                        || shouldListenForFingerprintAssistant
                         || (mKeyguardOccluded && mIsDreaming)
                         || (mKeyguardOccluded && userDoesNotHaveTrust
                             && (mOccludingAppRequestingFp || isUdfps));
 
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
+        final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
+        final boolean userCanSkipBouncer = getUserCanSkipBouncer(user);
+        final boolean fingerprintDisabledForUser = isFingerprintDisabled(user);
         final boolean shouldListenUserState =
                 !mSwitchingUser
-                        && !isFingerprintDisabled(getCurrentUser())
+                        && !fingerprintDisabledForUser
                         && (!mKeyguardGoingAway || !mDeviceInteractive)
                         && mIsPrimaryUser
-                        && mBiometricEnabledForUser.get(getCurrentUser());
+                        && biometricEnabledForUser;
 
         final boolean shouldListenBouncerState =
                 !(mFingerprintLockedOut && mBouncer && mCredentialAttempted);
 
+        final boolean isEncryptedOrLockdownForUser = isEncryptedOrLockdown(user);
+        final boolean userNeedsStrongAuth = userNeedsStrongAuth();
         final boolean shouldListenUdfpsState = !isUdfps
-                || (!getUserCanSkipBouncer(getCurrentUser())
-                    && !isEncryptedOrLockdown(getCurrentUser())
-                    && !userNeedsStrongAuth()
+                || (!userCanSkipBouncer
+                    && !isEncryptedOrLockdownForUser
+                    && !userNeedsStrongAuth
                     && userDoesNotHaveTrust
                     && !mFingerprintLockedOut);
-        return shouldListenKeyguardState && shouldListenUserState && shouldListenBouncerState
-                && shouldListenUdfpsState;
+
+        final boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
+                && shouldListenBouncerState && shouldListenUdfpsState;
+
+        if (DEBUG_FINGERPRINT || DEBUG_SPEW) {
+            maybeLogListenerModelData(
+                    new KeyguardFingerprintListenModel(
+                        System.currentTimeMillis(),
+                        user,
+                        shouldListen,
+                        biometricEnabledForUser,
+                        mBouncer,
+                        userCanSkipBouncer,
+                        mCredentialAttempted,
+                        mDeviceInteractive,
+                        mIsDreaming,
+                        isEncryptedOrLockdownForUser,
+                        fingerprintDisabledForUser,
+                        mFingerprintLockedOut,
+                        mGoingToSleep,
+                        mKeyguardGoingAway,
+                        mKeyguardIsVisible,
+                        mKeyguardOccluded,
+                        mOccludingAppRequestingFp,
+                        mIsPrimaryUser,
+                        shouldListenForFingerprintAssistant,
+                        mSwitchingUser,
+                        isUdfps,
+                        userDoesNotHaveTrust,
+                        userNeedsStrongAuth));
+        }
+
+        return shouldListen;
     }
 
     /**
@@ -2283,12 +2317,12 @@
                 containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
                         || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
 
-        boolean canBypass = mKeyguardBypassController != null
+        final boolean canBypass = mKeyguardBypassController != null
                 && mKeyguardBypassController.canBypass();
         // There's no reason to ask the HAL for authentication when the user can dismiss the
         // bouncer, unless we're bypassing and need to auto-dismiss the lock screen even when
         // TrustAgents or biometrics are keeping the device unlocked.
-        boolean becauseCannotSkipBouncer = !getUserCanSkipBouncer(user) || canBypass;
+        final boolean becauseCannotSkipBouncer = !getUserCanSkipBouncer(user) || canBypass;
 
         // Scan even when encrypted or timeout to show a preemptive bouncer when bypassing.
         // Lock-down mode shouldn't scan, since it is more explicit.
@@ -2296,69 +2330,72 @@
 
         // If the device supports face detection (without authentication), allow it to happen
         // if the device is in lockdown mode. Otherwise, prevent scanning.
-        boolean supportsDetectOnly = !mFaceSensorProperties.isEmpty()
+        final boolean supportsDetectOnly = !mFaceSensorProperties.isEmpty()
                 && mFaceSensorProperties.get(0).supportsFaceDetection;
         if (isLockDown && !supportsDetectOnly) {
             strongAuthAllowsScanning = false;
         }
 
         // If the face has recently been authenticated do not attempt to authenticate again.
-        boolean faceAuthenticated = getIsFaceAuthenticated();
+        final boolean faceAuthenticated = getIsFaceAuthenticated();
+        final boolean faceDisabledForUser = isFaceDisabled(user);
+        final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
+        final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant();
 
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
         final boolean shouldListen =
                 (mBouncer || mAuthInterruptActive || mOccludingAppRequestingFace || awakeKeyguard
-                        || shouldListenForFaceAssistant())
-                && !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
-                && !mKeyguardGoingAway && mBiometricEnabledForUser.get(user) && !mLockIconPressed
+                        || shouldListenForFaceAssistant)
+                && !mSwitchingUser && !faceDisabledForUser && becauseCannotSkipBouncer
+                && !mKeyguardGoingAway && biometricEnabledForUser && !mLockIconPressed
                 && strongAuthAllowsScanning && mIsPrimaryUser
                 && (!mSecureCameraLaunched || mOccludingAppRequestingFace)
                 && !faceAuthenticated;
 
         // Aggregate relevant fields for debug logging.
         if (DEBUG_FACE || DEBUG_SPEW) {
-            final KeyguardFaceListenModel model = new KeyguardFaceListenModel(
-                    System.currentTimeMillis(),
-                    user,
-                    shouldListen,
-                    mBouncer,
-                    mAuthInterruptActive,
-                    mOccludingAppRequestingFace,
-                    awakeKeyguard,
-                    shouldListenForFaceAssistant(),
-                    mSwitchingUser,
-                    isFaceDisabled(user),
-                    becauseCannotSkipBouncer,
-                    mKeyguardGoingAway,
-                    mBiometricEnabledForUser.get(user),
-                    mLockIconPressed,
-                    strongAuthAllowsScanning,
-                    mIsPrimaryUser,
-                    mSecureCameraLaunched,
-                    faceAuthenticated);
-            maybeLogFaceListenerModelData(model);
+            maybeLogListenerModelData(
+                    new KeyguardFaceListenModel(
+                        System.currentTimeMillis(),
+                        user,
+                        shouldListen,
+                        mAuthInterruptActive,
+                        becauseCannotSkipBouncer,
+                        biometricEnabledForUser,
+                        mBouncer,
+                        faceAuthenticated,
+                        faceDisabledForUser,
+                        awakeKeyguard,
+                        mKeyguardGoingAway,
+                        shouldListenForFaceAssistant,
+                        mLockIconPressed,
+                        mOccludingAppRequestingFace,
+                        mIsPrimaryUser,
+                        strongAuthAllowsScanning,
+                        mSecureCameraLaunched,
+                        mSwitchingUser));
         }
 
         return shouldListen;
     }
 
-    private void maybeLogFaceListenerModelData(KeyguardFaceListenModel model) {
+    private void maybeLogListenerModelData(KeyguardListenModel model) {
         // Too chatty, but very useful when debugging issues.
         if (DEBUG_SPEW) {
             Log.v(TAG, model.toString());
         }
 
         // Add model data to the historical buffer.
-        if (DEBUG_FACE && mFaceRunningState != BIOMETRIC_STATE_RUNNING
-                && model.isListeningForFace()) {
-            if (mFaceListenModels == null) {
-                mFaceListenModels = new ArrayDeque<>(FACE_LISTEN_CALLS_QUEUE_SIZE);
-            }
-            if (mFaceListenModels.size() >= FACE_LISTEN_CALLS_QUEUE_SIZE) {
-                mFaceListenModels.remove();
-            }
-            mFaceListenModels.add(model);
+        final boolean notYetRunning =
+                (DEBUG_FACE
+                    && model instanceof KeyguardFaceListenModel
+                    && mFaceRunningState != BIOMETRIC_STATE_RUNNING)
+                || (DEBUG_FINGERPRINT
+                    && model instanceof KeyguardFingerprintListenModel
+                    && mFingerprintRunningState != BIOMETRIC_STATE_RUNNING);
+        if (notYetRunning && model.getListening()) {
+            mListenModels.add(model);
         }
     }
 
@@ -3452,15 +3489,8 @@
             pw.println("    enabledByUser=" + mBiometricEnabledForUser.get(userId));
             pw.println("    mSecureCameraLaunched=" + mSecureCameraLaunched);
         }
-        if (mFaceListenModels != null && !mFaceListenModels.isEmpty()) {
-            final SimpleDateFormat dateFormat =
-                    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
-            pw.println("  Face listen results (last " + FACE_LISTEN_CALLS_QUEUE_SIZE + " calls):");
-            for (final KeyguardFaceListenModel model : mFaceListenModels) {
-                final String time = dateFormat.format(new Date(model.getTimeMillis()));
-                pw.println("    " + time + " " + model.toString());
-            }
-        }
+        mListenModels.print(pw);
+
         if (mIsAutomotive) {
             pw.println("  Running on Automotive build");
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 4317e25..509ac8a 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -514,7 +514,15 @@
                     if (!wasClickableOnDownEvent()) {
                         return false;
                     }
+                    onAffordanceClick();
+                    return true;
+                }
 
+                public boolean onFling(MotionEvent e1, MotionEvent e2,
+                        float velocityX, float velocityY) {
+                    if (!wasClickableOnDownEvent()) {
+                        return false;
+                    }
                     onAffordanceClick();
                     return true;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 3c37ede..b9440c5 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -24,23 +24,17 @@
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.annotation.IntDef;
-import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Handler;
+import android.os.UserHandle;
 import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -53,15 +47,10 @@
 import com.android.systemui.DualToneHandler;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -69,7 +58,7 @@
 import java.text.NumberFormat;
 
 public class BatteryMeterView extends LinearLayout implements
-        BatteryStateChangeCallback, Tunable, DarkReceiver {
+        BatteryStateChangeCallback, DarkReceiver {
 
     @Retention(SOURCE)
     @IntDef({MODE_DEFAULT, MODE_ON, MODE_OFF, MODE_ESTIMATE})
@@ -80,21 +69,15 @@
     public static final int MODE_ESTIMATE = 3;
 
     private final ThemedBatteryDrawable mDrawable;
-    private final String mSlotBattery;
     private final ImageView mBatteryIconView;
-    private final CurrentUserTracker mUserTracker;
     private TextView mBatteryPercentView;
 
     private BatteryController mBatteryController;
-    private SettingObserver mSettingObserver;
     private final @StyleRes int mPercentageStyleId;
     private int mTextColor;
     private int mLevel;
     private int mShowPercentMode = MODE_DEFAULT;
     private boolean mShowPercentAvailable;
-    // Some places may need to show the battery conditionally, and not obey the tuner
-    private boolean mIgnoreTunerUpdates;
-    private boolean mIsSubscribedForTunerUpdates;
     private boolean mCharging;
     // Error state where we know nothing about the current battery state
     private boolean mBatteryStateUnknown;
@@ -102,7 +85,6 @@
     private Drawable mUnknownStateDrawable;
 
     private DualToneHandler mDualToneHandler;
-    private int mUser;
 
     private int mNonAdaptedSingleToneColor;
     private int mNonAdaptedForegroundColor;
@@ -114,7 +96,6 @@
 
     public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        BroadcastDispatcher broadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
 
         setOrientation(LinearLayout.HORIZONTAL);
         setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
@@ -127,14 +108,11 @@
         mDrawable = new ThemedBatteryDrawable(context, frameColor);
         atts.recycle();
 
-        mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
         mShowPercentAvailable = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_battery_percentage_setting_available);
 
         setupLayoutTransition();
 
-        mSlotBattery = context.getString(
-                com.android.internal.R.string.status_bar_battery);
         mBatteryIconView = new ImageView(context);
         mBatteryIconView.setImageDrawable(mDrawable);
         final MarginLayoutParams mlp = new MarginLayoutParams(
@@ -149,18 +127,6 @@
         // Init to not dark at all.
         onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
 
-        mUserTracker = new CurrentUserTracker(broadcastDispatcher) {
-            @Override
-            public void onUserSwitched(int newUserId) {
-                mUser = newUserId;
-                getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
-                getContext().getContentResolver().registerContentObserver(
-                        Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver,
-                        newUserId);
-                updateShowPercent();
-            }
-        };
-
         setClipChildren(false);
         setClipToPadding(false);
     }
@@ -199,44 +165,6 @@
         updateShowPercent();
     }
 
-    /**
-     * Set {@code true} to turn off BatteryMeterView's subscribing to the tuner for updates, and
-     * thus avoid it controlling its own visibility
-     *
-     * @param ignore whether to ignore the tuner or not
-     */
-    public void setIgnoreTunerUpdates(boolean ignore) {
-        mIgnoreTunerUpdates = ignore;
-        updateTunerSubscription();
-    }
-
-    private void updateTunerSubscription() {
-        if (mIgnoreTunerUpdates) {
-            unsubscribeFromTunerUpdates();
-        } else {
-            subscribeForTunerUpdates();
-        }
-    }
-
-    private void subscribeForTunerUpdates() {
-        if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) {
-            return;
-        }
-
-        Dependency.get(TunerService.class)
-                .addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
-        mIsSubscribedForTunerUpdates = true;
-    }
-
-    private void unsubscribeFromTunerUpdates() {
-        if (!mIsSubscribedForTunerUpdates) {
-            return;
-        }
-
-        Dependency.get(TunerService.class).removeTunable(this);
-        mIsSubscribedForTunerUpdates = false;
-    }
-
     public void setColorsFromContext(Context context) {
         if (context == null) {
             return;
@@ -251,37 +179,17 @@
     }
 
     @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
-            ArraySet<String> icons = StatusBarIconController.getIconHideList(
-                    getContext(), newValue);
-            setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
-        }
-    }
-
-    @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
         mBatteryController = Dependency.get(BatteryController.class);
         mBatteryController.addCallback(this);
-        mUser = ActivityManager.getCurrentUser();
-        getContext().getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
-        getContext().getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME),
-                false, mSettingObserver);
         updateShowPercent();
-        subscribeForTunerUpdates();
-        mUserTracker.startTracking();
     }
 
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mUserTracker.stopTracking();
         mBatteryController.removeCallback(this);
-        getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
-        unsubscribeFromTunerUpdates();
     }
 
     @Override
@@ -314,7 +222,7 @@
         updateShowPercent();
     }
 
-    private void updatePercentText() {
+    void updatePercentText() {
         if (mBatteryStateUnknown) {
             setContentDescription(getContext().getString(R.string.accessibility_battery_unknown));
             return;
@@ -360,12 +268,12 @@
                         : R.string.accessibility_battery_level, mLevel));
     }
 
-    private void updateShowPercent() {
+    void updateShowPercent() {
         final boolean showing = mBatteryPercentView != null;
         // TODO(b/140051051)
         final boolean systemSetting = 0 != whitelistIpcs(() -> Settings.System
                 .getIntForUser(getContext().getContentResolver(),
-                SHOW_BATTERY_PERCENT, 0, mUser));
+                SHOW_BATTERY_PERCENT, 0, UserHandle.USER_CURRENT));
         boolean shouldShow =
                 (mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF)
                 || mShowPercentMode == MODE_ON
@@ -482,21 +390,5 @@
         pw.println("    mLevel: " + mLevel);
         pw.println("    mMode: " + mShowPercentMode);
     }
-
-    private final class SettingObserver extends ContentObserver {
-        public SettingObserver(Handler handler) {
-            super(handler);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            super.onChange(selfChange, uri);
-            updateShowPercent();
-            if (TextUtils.equals(uri.getLastPathSegment(),
-                    Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)) {
-                // update the text for sure if the estimate in the cache was updated
-                updatePercentText();
-            }
-        }
-    }
 }
+
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
index 198aa4a..4664423 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -15,7 +15,24 @@
  */
 package com.android.systemui.battery;
 
+import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.view.View;
+
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.ViewController;
 
 import javax.inject.Inject;
@@ -23,6 +40,12 @@
 /** Controller for {@link BatteryMeterView}. **/
 public class BatteryMeterViewController extends ViewController<BatteryMeterView> {
     private final ConfigurationController mConfigurationController;
+    private final TunerService mTunerService;
+    private final ContentResolver mContentResolver;
+
+    private final String mSlotBattery;
+    private final SettingObserver mSettingObserver;
+    private final CurrentUserTracker mCurrentUserTracker;
 
     private final ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
@@ -32,17 +55,54 @@
                 }
             };
 
+    private final TunerService.Tunable mTunable = new TunerService.Tunable() {
+        @Override
+        public void onTuningChanged(String key, String newValue) {
+            if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+                ArraySet<String> icons = StatusBarIconController.getIconHideList(
+                        getContext(), newValue);
+                mView.setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
+            }
+        }
+    };
+
+    // Some places may need to show the battery conditionally, and not obey the tuner
+    private boolean mIgnoreTunerUpdates;
+    private boolean mIsSubscribedForTunerUpdates;
+
     @Inject
     public BatteryMeterViewController(
             BatteryMeterView view,
-            ConfigurationController configurationController) {
+            ConfigurationController configurationController,
+            TunerService tunerService,
+            BroadcastDispatcher broadcastDispatcher,
+            @Main Handler mainHandler,
+            ContentResolver contentResolver) {
         super(view);
         mConfigurationController = configurationController;
+        mTunerService = tunerService;
+        mContentResolver = contentResolver;
+
+        mSlotBattery = getResources().getString(com.android.internal.R.string.status_bar_battery);
+        mSettingObserver = new SettingObserver(mainHandler);
+        mCurrentUserTracker = new CurrentUserTracker(broadcastDispatcher) {
+            @Override
+            public void onUserSwitched(int newUserId) {
+                contentResolver.unregisterContentObserver(mSettingObserver);
+                registerShowBatteryPercentObserver(newUserId);
+                mView.updateShowPercent();
+            }
+        };
     }
 
     @Override
     protected void onViewAttached() {
         mConfigurationController.addCallback(mConfigurationListener);
+        subscribeForTunerUpdates();
+
+        registerShowBatteryPercentObserver(ActivityManager.getCurrentUser());
+        registerGlobalBatteryUpdateObserver();
+        mCurrentUserTracker.startTracking();
     }
 
     @Override
@@ -54,5 +114,67 @@
     public void destroy() {
         super.destroy();
         mConfigurationController.removeCallback(mConfigurationListener);
+        unsubscribeFromTunerUpdates();
+        mCurrentUserTracker.stopTracking();
+        mContentResolver.unregisterContentObserver(mSettingObserver);
     }
-}
\ No newline at end of file
+
+    /**
+     * Turn off {@link BatteryMeterView}'s subscribing to the tuner for updates, and thus avoid it
+     * controlling its own visibility.
+     */
+    public void ignoreTunerUpdates() {
+        mIgnoreTunerUpdates = true;
+        unsubscribeFromTunerUpdates();
+    }
+
+    private void subscribeForTunerUpdates() {
+        if (mIsSubscribedForTunerUpdates || mIgnoreTunerUpdates) {
+            return;
+        }
+
+        mTunerService.addTunable(mTunable, StatusBarIconController.ICON_HIDE_LIST);
+        mIsSubscribedForTunerUpdates = true;
+    }
+
+    private void unsubscribeFromTunerUpdates() {
+        if (!mIsSubscribedForTunerUpdates) {
+            return;
+        }
+
+        mTunerService.removeTunable(mTunable);
+        mIsSubscribedForTunerUpdates = false;
+    }
+
+    private void registerShowBatteryPercentObserver(int user) {
+        mContentResolver.registerContentObserver(
+                Settings.System.getUriFor(SHOW_BATTERY_PERCENT),
+                false,
+                mSettingObserver,
+                user);
+    }
+
+    private void registerGlobalBatteryUpdateObserver() {
+        mContentResolver.registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME),
+                false,
+                mSettingObserver);
+    }
+
+    private final class SettingObserver extends ContentObserver {
+        public SettingObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            mView.updateShowPercent();
+            if (TextUtils.equals(uri.getLastPathSegment(),
+                    Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)) {
+                // update the text for sure if the estimate in the cache was updated
+                mView.updatePercentText();
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
index 98ad875..ae3e94b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
@@ -44,11 +44,17 @@
     private static final String TAG = "BiometricPrompt/AuthBiometricFaceToFingerprintView";
 
     protected static class UdfpsIconController extends IconController {
+        @BiometricState private int mIconState = STATE_IDLE;
+
         protected UdfpsIconController(
                 @NonNull Context context, @NonNull ImageView iconView, @NonNull TextView textView) {
             super(context, iconView, textView);
         }
 
+        void updateState(@BiometricState int newState) {
+            updateState(mIconState, newState);
+        }
+
         @Override
         protected void updateState(int lastState, int newState) {
             final boolean lastStateIsErrorIcon =
@@ -86,6 +92,7 @@
             }
 
             mState = newState;
+            mIconState = newState;
         }
     }
 
@@ -191,11 +198,11 @@
 
                 // Deactivate the face icon controller so it stops drawing to the view
                 mFaceIconController.deactivate();
-                // Then, activate this icon controller. We need to start in the "error" state
-                mUdfpsIconController.updateState(mState, newState);
+                // Then, activate this icon controller. We need to start in the "idle" state
+                mUdfpsIconController.updateState(STATE_IDLE);
             }
         } else { // Fingerprint
-            mUdfpsIconController.updateState(mState, newState);
+            mUdfpsIconController.updateState(newState);
         }
 
         super.updateState(newState);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
index 15e3f3a..5c6478e 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
@@ -21,8 +21,8 @@
 private const val MILLIS_PER_MINUTES = 1000 * 60f
 private const val BURN_IN_PREVENTION_PERIOD_Y = 521f
 private const val BURN_IN_PREVENTION_PERIOD_X = 83f
-private const val BURN_IN_PREVENTION_PERIOD_SCALE = 180f
-private const val BURN_IN_PREVENTION_PERIOD_PROGRESS = 120f
+private const val BURN_IN_PREVENTION_PERIOD_SCALE = 181f
+private const val BURN_IN_PREVENTION_PERIOD_PROGRESS = 89f
 
 /**
  * Returns the translation offset that should be used to avoid burn in at
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 5293c88..b2def7a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -466,7 +466,7 @@
     }
 
     boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
-        return !device.getFeatures().contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK);
+        return !isActiveRemoteDevice(device);
     }
 
     private final MediaController.Callback mCb = new MediaController.Callback() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 6bf9eb4..9e6a8b8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -133,8 +133,6 @@
 
         updateResources();
 
-        // Don't need to worry about tuner settings for this icon
-        mBatteryRemainingIcon.setIgnoreTunerUpdates(true);
         // QS will always show the estimate, and BatteryMeterView handles the case where
         // it's unavailable or charging
         mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 73d1489..df60100 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -171,6 +171,9 @@
         mCameraSlot = getResources().getString(com.android.internal.R.string.status_bar_camera);
         mMicSlot = getResources().getString(com.android.internal.R.string.status_bar_microphone);
         mLocationSlot = getResources().getString(com.android.internal.R.string.status_bar_location);
+
+        // Don't need to worry about tuner settings for this icon
+        mBatteryMeterViewController.ignoreTunerUpdates();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index db553e4..002c9c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -178,7 +178,8 @@
                 blurUtils.minBlurRadius, blurUtils.maxBlurRadius)
         var combinedBlur = (shadeSpring.radius * INTERACTION_BLUR_FRACTION +
                 normalizedBlurRadius * ANIMATION_BLUR_FRACTION).toInt()
-        combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsPanelExpansion))
+        val qsExpandedRatio = qsPanelExpansion * shadeExpansion
+        combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio))
         combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
         var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius).toFloat()
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index d2a4a00..c52a094 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -84,8 +84,8 @@
     private final WindowManager mWindowManager;
     private final IActivityManager mActivityManager;
     private final DozeParameters mDozeParameters;
+    private final KeyguardStateController mKeyguardStateController;
     private final LayoutParams mLpChanged;
-    private final boolean mKeyguardScreenRotation;
     private final long mLockScreenDisplayTimeout;
     private final float mKeyguardPreferredRefreshRate; // takes precedence over max
     private final float mKeyguardMaxRefreshRate;
@@ -123,8 +123,8 @@
         mContext = context;
         mWindowManager = windowManager;
         mActivityManager = activityManager;
-        mKeyguardScreenRotation = keyguardStateController.isKeyguardScreenRotationAllowed();
         mDozeParameters = dozeParameters;
+        mKeyguardStateController = keyguardStateController;
         mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
         mLpChanged = new LayoutParams();
         mKeyguardViewMediator = keyguardViewMediator;
@@ -323,7 +323,7 @@
 
     private void adjustScreenOrientation(State state) {
         if (state.isKeyguardShowingAndNotOccluded() || state.mDozing) {
-            if (mKeyguardScreenRotation) {
+            if (mKeyguardStateController.isKeyguardScreenRotationAllowed()) {
                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
             } else {
                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
index 0a5fa1e..4b7fe4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SplitShadeHeaderController.kt
@@ -20,8 +20,8 @@
 import com.android.systemui.R
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
-import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
 import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SPLIT_SHADE_HEADER
 import javax.inject.Inject
@@ -54,11 +54,12 @@
         }
 
     init {
-        val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon)
-        // battery settings same as in QS icons
-        batteryIcon.setIgnoreTunerUpdates(true)
-        batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
         batteryMeterViewController.init()
+        val batteryIcon: BatteryMeterView = statusBar.findViewById(R.id.batteryRemainingIcon)
+
+        // battery settings same as in QS icons
+        batteryMeterViewController.ignoreTunerUpdates()
+        batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
 
         val iconContainer: StatusIconContainer = statusBar.findViewById(R.id.statusIcons)
         iconManager = StatusBarIconController.IconManager(iconContainer, featureFlags)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 344653c..cbc852b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -224,6 +224,7 @@
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.wmshell.BubblesManager;
 import com.android.unfold.config.UnfoldTransitionConfig;
@@ -540,6 +541,7 @@
     private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     private final WallpaperManager mWallpaperManager;
     private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    private final TunerService mTunerService;
 
     private final List<ExpansionChangedListener> mExpansionChangedListeners;
 
@@ -873,7 +875,8 @@
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
             WallpaperManager wallpaperManager,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            Optional<StartingSurface> startingSurfaceOptional) {
+            Optional<StartingSurface> startingSurfaceOptional,
+            TunerService tunerService) {
         super(context);
         mNotificationsController = notificationsController;
         mLightBarController = lightBarController;
@@ -956,6 +959,7 @@
         mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
         mWallpaperManager = wallpaperManager;
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
+        mTunerService = tunerService;
 
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
         mStartingSurfaceOptional = startingSurfaceOptional;
@@ -1212,7 +1216,12 @@
                     mPhoneStatusBarViewController.init();
 
                     mBatteryMeterViewController = new BatteryMeterViewController(
-                            mStatusBarView.findViewById(R.id.battery), mConfigurationController
+                            mStatusBarView.findViewById(R.id.battery),
+                            mConfigurationController,
+                            mTunerService,
+                            mBroadcastDispatcher,
+                            mMainThreadHandler,
+                            mContext.getContentResolver()
                     );
                     mBatteryMeterViewController.init();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index a5b868b..6b52dca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -149,14 +149,18 @@
         lightRevealAnimationPlaying = false
         aodUiAnimationPlaying = false
 
-        // Make sure the status bar is in the correct keyguard state, forcing it if necessary. This
-        // is required if the screen off animation is cancelled, since it might be incorrectly left
-        // in the KEYGUARD or SHADE states depending on when it was cancelled and whether 'lock
-        // instantly' is enabled. We need to force it so that the state is set even if we're going
-        // from SHADE to SHADE or KEYGUARD to KEYGUARD, since we might have changed parts of the UI
-        // (such as showing AOD in the shade) without actually changing the StatusBarState. This
-        // ensures that the UI definitely reflects the desired state.
-        statusBar.updateIsKeyguard(true /* force */)
+        // If we can't control the screen off animation, we shouldn't mess with the StatusBar's
+        // keyguard state unnecessarily.
+        if (dozeParameters.get().canControlUnlockedScreenOff()) {
+            // Make sure the status bar is in the correct keyguard state, forcing it if necessary.
+            // This is required if the screen off animation is cancelled, since it might be
+            // incorrectly left in the KEYGUARD or SHADE states depending on when it was cancelled
+            // and whether 'lock instantly' is enabled. We need to force it so that the state is set
+            // even if we're going from SHADE to SHADE or KEYGUARD to KEYGUARD, since we might have
+            // changed parts of the UI (such as showing AOD in the shade) without actually changing
+            // the StatusBarState. This ensures that the UI definitely reflects the desired state.
+            statusBar.updateIsKeyguard(true /* force */)
+        }
     }
 
     override fun onStartedGoingToSleep() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 7ad0e7f..eabb2ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -99,6 +99,7 @@
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.wmshell.BubblesManager;
 import com.android.unfold.config.UnfoldTransitionConfig;
@@ -212,7 +213,8 @@
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
             WallpaperManager wallpaperManager,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
-            Optional<StartingSurface> startingSurfaceOptional) {
+            Optional<StartingSurface> startingSurfaceOptional,
+            TunerService tunerService) {
         return new StatusBar(
                 context,
                 notificationsController,
@@ -298,6 +300,7 @@
                 keyguardUnlockAnimationController,
                 wallpaperManager,
                 unlockedScreenOffAnimationController,
-                startingSurfaceOptional);
+                startingSurfaceOptional,
+                tunerService);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 1db6ce4..62ba56a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -216,6 +216,10 @@
         isCallAppVisible = isProcessVisibleToUser(
                 iActivityManager.getUidProcessState(currentCallNotificationInfo.uid, null))
 
+        if (uidObserver != null) {
+            iActivityManager.unregisterUidObserver(uidObserver)
+        }
+
         uidObserver = object : IUidObserver.Stub() {
             override fun onUidStateChanged(
                 uid: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 39a8bd9..dbdc460 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -25,6 +25,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.SystemWindows;
@@ -58,10 +59,10 @@
     @WMSingleton
     @Provides
     static DisplayImeController provideDisplayImeController(IWindowManager wmService,
-            DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor,
-            TransactionPool transactionPool) {
-        return new DisplayImeController(wmService, displayController, mainExecutor,
-                transactionPool);
+            DisplayController displayController, DisplayInsetsController displayInsetsController,
+            @ShellMainThread ShellExecutor mainExecutor, TransactionPool transactionPool) {
+        return new DisplayImeController(wmService, displayController, displayInsetsController,
+                mainExecutor, transactionPool);
     }
 
     //
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 7e3553a..7937dfd 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -44,6 +44,7 @@
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
@@ -110,6 +111,14 @@
 
     @WMSingleton
     @Provides
+    static DisplayInsetsController provideDisplayInsetsController( IWindowManager wmService,
+            DisplayController displayController,
+            @ShellMainThread ShellExecutor mainExecutor) {
+        return new DisplayInsetsController(wmService, displayController, mainExecutor);
+    }
+
+    @WMSingleton
+    @Provides
     static DisplayLayout provideDisplayLayout() {
         return new DisplayLayout();
     }
@@ -452,7 +461,9 @@
 
     @WMSingleton
     @Provides
-    static ShellInitImpl provideShellInitImpl(DisplayImeController displayImeController,
+    static ShellInitImpl provideShellInitImpl(DisplayController displayController,
+            DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController,
             DragAndDropController dragAndDropController,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<BubbleController> bubblesOptional,
@@ -465,7 +476,9 @@
             Transitions transitions,
             StartingWindowController startingWindow,
             @ShellMainThread ShellExecutor mainExecutor) {
-        return new ShellInitImpl(displayImeController,
+        return new ShellInitImpl(displayController,
+                displayImeController,
+                displayInsetsController,
                 dragAndDropController,
                 shellTaskOrganizer,
                 bubblesOptional,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 6397ce6..83c2a9b 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -28,6 +28,7 @@
 import com.android.wm.shell.apppairs.AppPairsController;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
@@ -83,10 +84,11 @@
     @WMSingleton
     @Provides
     static DisplayImeController provideDisplayImeController(IWindowManager wmService,
-            DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor,
+            DisplayController displayController, DisplayInsetsController displayInsetsController,
+            @ShellMainThread ShellExecutor mainExecutor,
             TransactionPool transactionPool) {
-        return new DisplayImeController(wmService, displayController, mainExecutor,
-                transactionPool);
+        return new DisplayImeController(wmService, displayController, displayInsetsController,
+                mainExecutor, transactionPool);
     }
 
     //
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
new file mode 100644
index 0000000..db87c5d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.keyguard
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class KeyguardListenQueueTest : SysuiTestCase() {
+
+    @Test
+    fun testQueueIsBounded() {
+        val size = 5
+        val queue = KeyguardListenQueue(sizePerModality = size)
+
+        val fingerprints = List(100) { fingerprintModel(it) }
+        fingerprints.forEach { queue.add(it) }
+
+        assertThat(queue.models).containsExactlyElementsIn(fingerprints.takeLast(size))
+
+        val faces = List(100) { faceModel(it) }
+        faces.forEach { queue.add(it) }
+
+        assertThat(queue.models).containsExactlyElementsIn(
+            faces.takeLast(size) + fingerprints.takeLast(5)
+        )
+
+        repeat(100) {
+            queue.add(faceModel(-1))
+            queue.add(fingerprintModel(-1))
+        }
+        assertThat(queue.models).hasSize(2 * size)
+        assertThat(queue.models.count { it.userId == -1 }).isEqualTo(2 * size)
+    }
+}
+
+private fun fingerprintModel(user: Int) = KeyguardFingerprintListenModel(
+    timeMillis = System.currentTimeMillis(),
+    userId = user,
+    listening = false,
+    biometricEnabledForUser = false,
+    bouncer = false,
+    canSkipBouncer = false,
+    credentialAttempted = false,
+    deviceInteractive = false,
+    dreaming = false,
+    encryptedOrLockdown = false,
+    fingerprintDisabled = false,
+    fingerprintLockedOut = false,
+    goingToSleep = false,
+    keyguardGoingAway = false,
+    keyguardIsVisible = false,
+    keyguardOccluded = false,
+    occludingAppRequestingFp = false,
+    primaryUser = false,
+    shouldListenForFingerprintAssistant = false,
+    switchingUser = false,
+    udfps = false,
+    userDoesNotHaveTrust = false,
+    userNeedsStrongAuth = false
+)
+
+private fun faceModel(user: Int) = KeyguardFaceListenModel(
+    timeMillis = System.currentTimeMillis(),
+    userId = user,
+    listening = false,
+    authInterruptActive = false,
+    becauseCannotSkipBouncer = false,
+    biometricSettingEnabledForUser = false,
+    bouncer = false,
+    faceAuthenticated = false,
+    faceDisabled = false,
+    keyguardAwake = false,
+    keyguardGoingAway = false,
+    listeningForFaceAssistant = false,
+    lockIconPressed = false,
+    occludingAppRequestingFaceAuth = false,
+    primaryUser = false,
+    scanningAllowedByStrongAuth = false,
+    secureCameraLaunched = false,
+    switchingUser = false
+)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
index 06e27b5..f09d7b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.View.OVER_SCROLL_ALWAYS;
 import static android.view.View.OVER_SCROLL_NEVER;
 import static android.view.WindowInsets.Type.ime;
@@ -134,7 +135,10 @@
         mMenuHalfHeight = menuHeight / 2;
         mScreenHalfWidth = screenWidth / 2;
         mScreenHalfHeight = mScreenHeight / 2;
-        mMaxWindowX = screenWidth - margin - menuWidth;
+        int marginStartEnd =
+                mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT
+                        ? margin : 0;
+        mMaxWindowX = screenWidth - marginStartEnd - menuWidth;
         mMenuWindowHeight = menuHeight + margin * 2;
         mMaxWindowY = mScreenHeight - mMenuWindowHeight;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
index 05bde5c..903cbb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
@@ -16,13 +16,27 @@
 
 package com.android.systemui.battery;
 
+import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+
+import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.eq;
+
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.os.Handler;
+import android.provider.Settings;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.tuner.TunerService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -36,6 +50,14 @@
 
     @Mock
     private ConfigurationController mConfigurationController;
+    @Mock
+    private TunerService mTunerService;
+    @Mock
+    private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private Handler mHandler;
+    @Mock
+    private ContentResolver mContentResolver;
 
     private BatteryMeterViewController mController;
 
@@ -43,9 +65,16 @@
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        when(mBatteryMeterView.getContext()).thenReturn(mContext);
+        when(mBatteryMeterView.getResources()).thenReturn(mContext.getResources());
+
         mController = new BatteryMeterViewController(
                 mBatteryMeterView,
-                mConfigurationController
+                mConfigurationController,
+                mTunerService,
+                mBroadcastDispatcher,
+                mHandler,
+                mContentResolver
         );
     }
 
@@ -54,6 +83,15 @@
         mController.onViewAttached();
 
         verify(mConfigurationController).addCallback(any());
+        verify(mTunerService).addTunable(any(), any());
+        verify(mContentResolver).registerContentObserver(
+                eq(Settings.System.getUriFor(SHOW_BATTERY_PERCENT)), anyBoolean(), any(), anyInt()
+        );
+        verify(mContentResolver).registerContentObserver(
+                eq(Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)),
+                anyBoolean(),
+                any()
+        );
     }
 
     @Test
@@ -64,5 +102,26 @@
         mController.onViewDetached();
 
         verify(mConfigurationController).removeCallback(any());
+        verify(mTunerService).removeTunable(any());
+        verify(mContentResolver).unregisterContentObserver(any());
+    }
+
+    @Test
+    public void ignoreTunerUpdates_afterOnViewAttached_callbackUnregistered() {
+        // Start out receiving tuner updates
+        mController.onViewAttached();
+
+        mController.ignoreTunerUpdates();
+
+        verify(mTunerService).removeTunable(any());
+    }
+
+    @Test
+    public void ignoreTunerUpdates_beforeOnViewAttached_callbackNeverRegistered() {
+        mController.ignoreTunerUpdates();
+
+        mController.onViewAttached();
+
+        verify(mTunerService, never()).addTunable(any(), any());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
index 090cf9f..f91c029 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
@@ -101,7 +101,7 @@
         mFaceToFpView.onDialogAnimatedIn();
         verify(mFaceToFpView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
-        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
+        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
     }
 
     @Test
@@ -109,13 +109,13 @@
         mFaceToFpView.onDialogAnimatedIn();
         verify(mFaceToFpView.mFaceIconController)
                 .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
-        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
+        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
 
         mFaceToFpView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
         verify(mFaceToFpView.mFaceIconController).updateState(
                 eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
                 eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED));
-        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt(), anyInt());
+        verify(mFaceToFpView.mUdfpsIconController, never()).updateState(anyInt());
 
         assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED, mFaceToFpView.mState);
     }
@@ -130,14 +130,12 @@
 
         verify(mFaceToFpView.mFaceIconController).deactivate();
         verify(mFaceToFpView.mUdfpsIconController).updateState(
-                eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
-                eq(AuthBiometricFaceToFingerprintView.STATE_ERROR));
+                eq(AuthBiometricFaceToFingerprintView.STATE_IDLE));
         verify(mConfirmButton).setVisibility(eq(View.GONE));
 
         mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
 
         verify(mFaceToFpView.mUdfpsIconController).updateState(
-                eq(AuthBiometricFaceToFingerprintView.STATE_ERROR),
                 eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index 8e1b13c..8cc2776 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -79,6 +79,7 @@
             configurationController
         )
         keyguardMediaController.attachSinglePaneContainer(mediaHeaderView)
+        keyguardMediaController.useSplitShade = false
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index d23a9ce..7c045c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -184,8 +184,9 @@
     @Test
     fun setQsPanelExpansion_appliesBlur() {
         notificationShadeDepthController.qsPanelExpansion = 1f
+        notificationShadeDepthController.onPanelExpansionChanged(0.5f, tracking = false)
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
-        verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
+        verify(blurUtils).applyBlur(any(), eq(maxBlur / 2), eq(false))
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index c06a9ae..e4f6e13d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -138,6 +138,7 @@
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.unfold.UnfoldLightRevealOverlayAnimation;
+import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.volume.VolumeComponent;
@@ -262,6 +263,7 @@
     @Mock private IWallpaperManager mIWallpaperManager;
     @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+    @Mock private TunerService mTunerService;
     @Mock private StartingSurface mStartingSurface;
     private ShadeController mShadeController;
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -425,7 +427,8 @@
                 mKeyguardUnlockAnimationController,
                 mWallpaperManager,
                 mUnlockedScreenOffAnimationController,
-                Optional.of(mStartingSurface));
+                Optional.of(mStartingSurface),
+                mTunerService);
         when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class),
                 any(NotificationPanelViewController.class), any(BiometricUnlockController.class),
                 any(ViewGroup.class), any(KeyguardBypassController.class)))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index 31fa04d..4476fd8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -184,6 +184,21 @@
                 .isGreaterThan(0)
     }
 
+    /** Regression test for b/194731244. */
+    @Test
+    fun onEntryUpdated_calledManyTimes_uidObserverUnregisteredManyTimes() {
+        val numCalls = 4
+
+        for (i in 0 until numCalls) {
+            // Re-create the notification each time so that it's considered a different object and
+            // observers will get re-registered (and hopefully unregistered).
+            notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
+        }
+
+        // There should be 1 observer still registered, so we should unregister n-1 times.
+        verify(mockIActivityManager, times(numCalls - 1)).unregisterUidObserver(any())
+    }
+
     /**
      * If a call notification is never added before #onEntryRemoved is called, then the listener
      * should never be notified.
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 5aec6aa..a56b1db 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -3285,6 +3285,57 @@
         }
     }
 
+    private void applyResourceOverlaysToWidgetsLocked(Set<String> packageNames, int userId,
+            boolean updateFrameworkRes) {
+        for (int i = 0, N = mProviders.size(); i < N; i++) {
+            Provider provider = mProviders.get(i);
+            if (provider.getUserId() != userId) {
+                continue;
+            }
+
+            final String packageName = provider.id.componentName.getPackageName();
+            if (!updateFrameworkRes && !packageNames.contains(packageName)) {
+                continue;
+            }
+
+            ApplicationInfo newAppInfo = null;
+            try {
+                newAppInfo = mPackageManager.getApplicationInfo(packageName,
+                        PackageManager.GET_SHARED_LIBRARY_FILES, userId);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to retrieve app info for " + packageName
+                        + " userId=" + userId, e);
+            }
+            if (newAppInfo == null) {
+                continue;
+            }
+            ApplicationInfo oldAppInfo = provider.info.providerInfo.applicationInfo;
+            if (!newAppInfo.sourceDir.equals(oldAppInfo.sourceDir)) {
+                // Overlay paths are generated against a particular version of an application.
+                // The overlays paths of a newly upgraded application are incompatible with the
+                // old version of the application.
+                continue;
+            }
+
+            // Isolate the changes relating to RROs. The app info must be copied to prevent
+            // affecting other parts of system server that may have cached this app info.
+            oldAppInfo = new ApplicationInfo(oldAppInfo);
+            oldAppInfo.overlayPaths = newAppInfo.overlayPaths.clone();
+            oldAppInfo.resourceDirs = newAppInfo.resourceDirs.clone();
+            provider.info.providerInfo.applicationInfo = oldAppInfo;
+
+            for (int j = 0, M = provider.widgets.size(); j < M; j++) {
+                Widget widget = provider.widgets.get(j);
+                if (widget.views != null) {
+                    widget.views.updateAppInfo(oldAppInfo);
+                }
+                if (widget.maskedViews != null) {
+                    widget.maskedViews.updateAppInfo(oldAppInfo);
+                }
+            }
+        }
+    }
+
     /**
      * Updates all providers with the specified package names, and records any providers that were
      * pruned.
@@ -4875,5 +4926,14 @@
         public void unlockUser(int userId) {
             handleUserUnlocked(userId);
         }
+
+        @Override
+        public void applyResourceOverlaysToWidgets(Set<String> packageNames, int userId,
+                boolean updateFrameworkRes) {
+            synchronized (mLock) {
+                applyResourceOverlaysToWidgetsLocked(new HashSet<>(packageNames), userId,
+                        updateFrameworkRes);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index d483f18..a03425c 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -26,6 +26,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.IVpnManager;
@@ -312,6 +314,26 @@
         }
     }
 
+    // TODO : Move to a static lib to factorize with Vpn.java
+    private int getAppUid(final String app, final int userId) {
+        final PackageManager pm = mContext.getPackageManager();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return pm.getPackageUidAsUser(app, userId);
+        } catch (NameNotFoundException e) {
+            return -1;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private void verifyCallingUidAndPackage(String packageName, int callingUid) {
+        final int userId = UserHandle.getUserId(callingUid);
+        if (getAppUid(packageName, userId) != callingUid) {
+            throw new SecurityException(packageName + " does not belong to uid " + callingUid);
+        }
+    }
+
     /**
      * Starts the VPN based on the stored profile for the given package
      *
@@ -323,7 +345,9 @@
      */
     @Override
     public void startVpnProfile(@NonNull String packageName) {
-        final int user = UserHandle.getUserId(mDeps.getCallingUid());
+        final int callingUid = Binder.getCallingUid();
+        verifyCallingUidAndPackage(packageName, callingUid);
+        final int user = UserHandle.getUserId(callingUid);
         synchronized (mVpns) {
             throwIfLockdownEnabled();
             mVpns.get(user).startVpnProfile(packageName);
@@ -340,7 +364,9 @@
      */
     @Override
     public void stopVpnProfile(@NonNull String packageName) {
-        final int user = UserHandle.getUserId(mDeps.getCallingUid());
+        final int callingUid = Binder.getCallingUid();
+        verifyCallingUidAndPackage(packageName, callingUid);
+        final int user = UserHandle.getUserId(callingUid);
         synchronized (mVpns) {
             mVpns.get(user).stopVpnProfile(packageName);
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f6510e6..85ffaa2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -193,6 +193,7 @@
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetManagerInternal;
 import android.content.AttributionSource;
 import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
@@ -16578,13 +16579,21 @@
         enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                 "scheduleApplicationInfoChanged()");
 
-        synchronized (mProcLock) {
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                updateApplicationInfoLOSP(packageNames, userId);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            final boolean updateFrameworkRes = packageNames.contains("android");
+            synchronized (mProcLock) {
+                updateApplicationInfoLOSP(packageNames, updateFrameworkRes, userId);
             }
+
+            AppWidgetManagerInternal widgets = LocalServices.getService(
+                    AppWidgetManagerInternal.class);
+            if (widgets != null) {
+                widgets.applyResourceOverlaysToWidgets(new HashSet<>(packageNames), userId,
+                        updateFrameworkRes);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -16601,11 +16610,12 @@
     }
 
     @GuardedBy(anyOf = {"this", "mProcLock"})
-    private void updateApplicationInfoLOSP(@NonNull List<String> packagesToUpdate, int userId) {
-        final boolean updateFrameworkRes = packagesToUpdate.contains("android");
+    private void updateApplicationInfoLOSP(@NonNull List<String> packagesToUpdate,
+            boolean updateFrameworkRes, int userId) {
         if (updateFrameworkRes) {
             ParsingPackageUtils.readConfigUseRoundIcon(null);
         }
+
         mProcessList.updateApplicationInfoLOSP(packagesToUpdate, userId, updateFrameworkRes);
 
         if (updateFrameworkRes) {
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9f806af..806bcc2 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -16,7 +16,9 @@
 
 package com.android.server.display;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.DisplayViewport;
 import android.os.IBinder;
@@ -105,6 +107,34 @@
     }
 
     /**
+     * Returns the window token of the level of the WindowManager hierarchy to mirror, or null
+     * if layer mirroring by SurfaceFlinger should not be performed.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    @Nullable
+    public IBinder getWindowTokenClientToMirrorLocked() {
+        return null;
+    }
+
+    /**
+     * Updates the window token of the level of the level of the WindowManager hierarchy to mirror.
+     * If windowToken is null, then no layer mirroring by SurfaceFlinger to should be performed.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    public void setWindowTokenClientToMirrorLocked(IBinder windowToken) {
+    }
+
+    /**
+     * Returns the default size of the surface associated with the display, or null if the surface
+     * is not provided for layer mirroring by SurfaceFlinger.
+     * For now, only used for mirroring started from MediaProjection.
+     */
+    @Nullable
+    public Point getDisplaySurfaceDefaultSize() {
+        return null;
+    }
+
+    /**
      * Gets the name of the display device.
      *
      * @return The display device name.
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a0944c0..1adcf40 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1765,10 +1765,13 @@
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
 
+        // Mirror the part of WM hierarchy that corresponds to the provided window token.
+        IBinder windowTokenClientToMirror = device.getWindowTokenClientToMirrorLocked();
+
         // Find the logical display that the display device is showing.
         // Certain displays only ever show their own content.
         LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
-        if (!ownContent) {
+        if (!ownContent && windowTokenClientToMirror == null) {
             if (display != null && !display.hasContentLocked()) {
                 // If the display does not have any content of its own, then
                 // automatically mirror the requested logical display contents if possible.
@@ -3330,6 +3333,40 @@
             }
             return config.getRefreshRateLimitations();
         }
+
+        @Override
+        public IBinder getWindowTokenClientToMirror(int displayId) {
+            final DisplayDevice device;
+            synchronized (mSyncRoot) {
+                device = getDeviceForDisplayLocked(displayId);
+                if (device == null) {
+                    return null;
+                }
+            }
+            return device.getWindowTokenClientToMirrorLocked();
+        }
+
+        @Override
+        public void setWindowTokenClientToMirror(int displayId, IBinder windowToken) {
+            synchronized (mSyncRoot) {
+                final DisplayDevice device = getDeviceForDisplayLocked(displayId);
+                if (device != null) {
+                    device.setWindowTokenClientToMirrorLocked(windowToken);
+                }
+            }
+        }
+
+        @Override
+        public Point getDisplaySurfaceDefaultSize(int displayId) {
+            final DisplayDevice device;
+            synchronized (mSyncRoot) {
+                device = getDeviceForDisplayLocked(displayId);
+                if (device == null) {
+                    return null;
+                }
+            }
+            return device.getDisplaySurfaceDefaultSize();
+        }
     }
 
     class DesiredDisplayModeSpecsObserver
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index b7931c8..34d2b01 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -31,7 +31,9 @@
 import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
 import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.graphics.Point;
 import android.hardware.display.IVirtualDisplayCallback;
 import android.hardware.display.VirtualDisplayConfig;
 import android.media.projection.IMediaProjection;
@@ -231,6 +233,7 @@
         private Display.Mode mMode;
         private boolean mIsDisplayOn;
         private int mDisplayIdToMirror;
+        private IBinder mWindowTokenClientToMirror;
 
         public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
                 int ownerUid, String ownerPackageName, Surface surface, int flags,
@@ -253,6 +256,7 @@
             mUniqueIndex = uniqueIndex;
             mIsDisplayOn = surface != null;
             mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror();
+            mWindowTokenClientToMirror = virtualDisplayConfig.getWindowTokenClientToMirror();
         }
 
         @Override
@@ -282,6 +286,26 @@
             return mDisplayIdToMirror;
         }
 
+        @Override
+        @Nullable
+        public IBinder getWindowTokenClientToMirrorLocked() {
+            return mWindowTokenClientToMirror;
+        }
+
+        @Override
+        public void setWindowTokenClientToMirrorLocked(IBinder windowToken) {
+            if (mWindowTokenClientToMirror != windowToken) {
+                mWindowTokenClientToMirror = windowToken;
+                sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+                sendTraversalRequestLocked();
+            }
+        }
+
+        @Override
+        public Point getDisplaySurfaceDefaultSize() {
+            return mSurface.getDefaultSize();
+        }
+
         @VisibleForTesting
         Surface getSurfaceLocked() {
             return mSurface;
@@ -362,6 +386,7 @@
             pw.println("mDisplayState=" + Display.stateToString(mDisplayState));
             pw.println("mStopped=" + mStopped);
             pw.println("mDisplayIdToMirror=" + mDisplayIdToMirror);
+            pw.println("mWindowTokenClientToMirror=" + mWindowTokenClientToMirror);
         }
 
 
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index db2a43f..2178672 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -192,9 +192,7 @@
 
     /** Logs a new incoming location for a location provider. */
     public void logProviderReceivedLocations(String provider, int numLocations) {
-        if (D) {
-            addLogEvent(EVENT_PROVIDER_RECEIVE_LOCATION, provider, numLocations);
-        }
+        addLogEvent(EVENT_PROVIDER_RECEIVE_LOCATION, provider, numLocations);
     }
 
     /** Logs a location deliver for a client of a location provider. */
diff --git a/services/core/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java
index 394cdee..83f54f1 100644
--- a/services/core/java/com/android/server/pm/PackageSignatures.java
+++ b/services/core/java/com/android/server/pm/PackageSignatures.java
@@ -174,7 +174,16 @@
                                 if (index >= 0 && index < readSignatures.size()) {
                                     Signature sig = readSignatures.get(index);
                                     if (sig != null) {
-                                        signatures.add(sig);
+                                        // An app using a shared signature in its signing lineage
+                                        // can have unique capabilities assigned to this previous
+                                        // signer; create a new instance of this Signature to ensure
+                                        // its flags do not overwrite those of the instance from
+                                        // readSignatures.
+                                        if (isPastSigs) {
+                                            signatures.add(new Signature(sig));
+                                        } else {
+                                            signatures.add(sig);
+                                        }
                                         signatureParsed = true;
                                     } else {
                                         PackageManagerService.reportSettingsProblem(Log.WARN,
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 6014d0c..2491565d 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -255,7 +255,11 @@
     private boolean checkTidValid(int uid, int tgid, int [] tids) {
         // Make sure all tids belongs to the same UID (including isolated UID),
         // tids can belong to different application processes.
-        List<Integer> eligiblePids = mAmInternal.getIsolatedProcesses(uid);
+        List<Integer> eligiblePids = null;
+        // To avoid deadlock, do not call into AMS if the call is from system.
+        if (uid != Process.SYSTEM_UID) {
+            eligiblePids = mAmInternal.getIsolatedProcesses(uid);
+        }
         if (eligiblePids == null) {
             eligiblePids = new ArrayList<>();
         }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index a45e8e0..54c660e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1179,7 +1179,7 @@
             header.run();
         }
 
-        String innerPrefix = prefix + "      ";
+        String innerPrefix = prefix + "  ";
         String[] args = new String[0];
         if (lastTask != r.getTask()) {
             lastTask = r.getTask();
@@ -2444,20 +2444,6 @@
         }
     }
 
-    private void removeAppTokenFromDisplay() {
-        if (mWmService.mRoot == null) return;
-
-        final DisplayContent dc = mWmService.mRoot.getDisplayContent(getDisplayId());
-        if (dc == null) {
-            Slog.w(TAG, "removeAppTokenFromDisplay: Attempted to remove token: "
-                    + appToken + " from non-existing displayId=" + getDisplayId());
-            return;
-        }
-        // Resume key dispatching if it is currently paused before we remove the container.
-        resumeKeyDispatchingLocked();
-        dc.removeAppToken(appToken.asBinder());
-    }
-
     /**
      * Reparents this activity into {@param newTaskFrag} at the provided {@param position}. The
      * caller should ensure that the {@param newTaskFrag} is not already the parent of this
@@ -3008,7 +2994,7 @@
     @interface FinishRequest {}
 
     /**
-     * See {@link #finishIfPossible(int, Intent, String, boolean)}
+     * See {@link #finishIfPossible(int, Intent, NeededUriGrants, String, boolean)}
      */
     @FinishRequest int finishIfPossible(String reason, boolean oomAdj) {
         return finishIfPossible(Activity.RESULT_CANCELED,
@@ -3470,7 +3456,9 @@
         setState(DESTROYED, "removeFromHistory");
         if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this);
         detachFromProcess();
-        removeAppTokenFromDisplay();
+        // Resume key dispatching if it is currently paused before we remove the container.
+        resumeKeyDispatchingLocked();
+        mDisplayContent.removeAppToken(appToken);
 
         cleanUpActivityServices();
         removeUriPermissionsLocked();
@@ -3687,12 +3675,17 @@
 
     @Override
     void removeImmediately() {
-        if (!isState(DESTROYING, DESTROYED)) {
+        if (mState != DESTROYED) {
+            Slog.w(TAG, "Force remove immediately " + this + " state=" + mState);
             // If Task#removeImmediately is called directly with alive activities, ensure that the
             // activities are destroyed and detached from process.
             destroyImmediately("removeImmediately");
+            // Complete the destruction immediately because this activity will not be found in
+            // hierarchy, it is unable to report completion.
+            destroyed("removeImmediately");
+        } else {
+            onRemovedFromDisplay();
         }
-        onRemovedFromDisplay();
         super.removeImmediately();
     }
 
@@ -6624,17 +6617,6 @@
         }
     }
 
-    boolean hasWindowsAlive() {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            // No need to loop through child windows as the answer should be the same as that of the
-            // parent window.
-            if (!(mChildren.get(i)).mAppDied) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     void setWillReplaceWindows(boolean animate) {
         ProtoLog.d(WM_DEBUG_ADD_REMOVE,
                 "Marking app token %s with replacing windows.", this);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c9f3356..3bc6435 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2682,7 +2682,7 @@
                             && mTargetRootTask != intentTask.getParent().asTask()) {
                         intentTask.getParent().positionChildAt(POSITION_TOP, intentTask,
                                 false /* includingParents */);
-                        intentTask = intentTask.getParent().asTask();
+                        intentTask = intentTask.getParent().asTaskFragment().getTask();
                     }
                     // If the task is in multi-windowing mode, the activity may already be on
                     // the top (visible to user but not the global top), then the result code
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index c869ec6..d6b0086 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -464,7 +464,8 @@
         }
         final RemoteAnimationAdapter adapter =
                 getRemoteAnimationOverride(animLpActivity, transit, activityTypes);
-        if (adapter != null) {
+        if (adapter != null
+                && mDisplayContent.mAppTransition.getRemoteAnimationController() == null) {
             mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 256d818..f5f2990 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -298,6 +298,22 @@
      */
     private final SurfaceControl mWindowingLayer;
 
+    /**
+     * The window token of the layer of the hierarchy to mirror, or null if this DisplayContent
+     * is not being used for layer mirroring.
+     */
+    @VisibleForTesting IBinder mTokenToMirror = null;
+
+    /**
+     * The surface for mirroring the contents of this hierarchy.
+     */
+    private SurfaceControl mMirroredSurface = null;
+
+    /**
+     * The last bounds of the DisplayArea to mirror.
+     */
+    private Rect mLastMirroredDisplayAreaBounds = null;
+
     // Contains all IME window containers. Note that the z-ordering of the IME windows will depend
     // on the IME target. We mainly have this container grouping so we can keep track of all the IME
     // window containers together and move them in-sync if/when needed. We use a subclass of
@@ -1126,6 +1142,10 @@
         if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display);
 
         mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
+
+        // Check if this DisplayContent is for a new VirtualDisplay, that should use layer mirroring
+        // to capture the contents of a DisplayArea.
+        startMirrorIfNeeded();
     }
 
     boolean isReady() {
@@ -1609,8 +1629,10 @@
             // If the transition has not started yet, the activity must be the top.
             return false;
         }
-        if (mLastWallpaperVisible && r.windowsCanBeWallpaperTarget()) {
-            // Use normal rotation animation for orientation change of visible wallpaper.
+        if (mLastWallpaperVisible && r.windowsCanBeWallpaperTarget()
+                && mFixedRotationTransitionListener.mAnimatingRecents == null) {
+            // Use normal rotation animation for orientation change of visible wallpaper if recents
+            // animation is not running (it may be swiping to home).
             return false;
         }
         final int rotation = rotationForActivityInDifferentOrientation(r);
@@ -2480,6 +2502,25 @@
         // Update IME parent if needed.
         updateImeParent();
 
+        // Update mirroring surface for MediaProjection, if this DisplayContent is being used
+        // for layer mirroring.
+        if (mMirroredSurface != null) {
+            // Retrieve the size of the DisplayArea to mirror, and continue with the update if the
+            // bounds have changed.
+            final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
+                    mTokenToMirror);
+            if (wc != null && mLastMirroredDisplayAreaBounds != null) {
+                // Retrieve the size of the DisplayArea to mirror, and continue with the update
+                // if the bounds or orientation has changed.
+                final Rect displayAreaBounds = wc.getDisplayContent().getBounds();
+                int displayAreaOrientation = wc.getDisplayContent().getOrientation();
+                if (!mLastMirroredDisplayAreaBounds.equals(displayAreaBounds)
+                        || lastOrientation != displayAreaOrientation) {
+                    updateMirroredSurface(mWmService.mTransactionFactory.get(), displayAreaBounds);
+                }
+            }
+        }
+
         if (lastOrientation != getConfiguration().orientation) {
             getMetricsLogger().write(
                     new LogMaker(MetricsEvent.ACTION_PHONE_ORIENTATION_CHANGED)
@@ -4338,6 +4379,7 @@
                     mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
                     true /* inTraversal, must call performTraversalInTrans... below */);
         }
+        updateMirroring();
 
         final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
         if (wallpaperVisible != mLastWallpaperVisible) {
@@ -5901,6 +5943,133 @@
         return mSandboxDisplayApis;
     }
 
+    /**
+     * Start mirroring to this DisplayContent if it does not have its own content. Captures the
+     * content of a WindowContainer indicated by a WindowToken. If unable to start mirroring, falls
+     * back to original MediaProjection approach.
+     */
+    private void startMirrorIfNeeded() {
+        // Only mirror if this display does not have its own content.
+        if (mLastHasContent) {
+            return;
+        }
+        // Given the WindowToken of the DisplayArea to mirror, retrieve the associated
+        // SurfaceControl.
+        IBinder tokenToMirror = mWmService.mDisplayManagerInternal.getWindowTokenClientToMirror(
+                mDisplayId);
+
+        if (tokenToMirror == null) {
+            // This DisplayContent instance is not involved in layer mirroring. If the display
+            // has been created for capturing, fall back to prior MediaProjection approach.
+            return;
+        }
+        final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
+                tokenToMirror);
+        if (wc == null) {
+            // Un-set the window token to mirror for this VirtualDisplay, to fall back to the
+            // original MediaProjection approach.
+            mWmService.mDisplayManagerInternal.setWindowTokenClientToMirror(mDisplayId, null);
+            return;
+        }
+        SurfaceControl sc = wc.getDisplayContent().getSurfaceControl();
+
+        // Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
+        mMirroredSurface = SurfaceControl.mirrorSurface(sc);
+        SurfaceControl.Transaction transaction = mWmService.mTransactionFactory.get()
+                // Set the mMirroredSurface's parent to the root SurfaceControl for this
+                // DisplayContent. This brings the new mirrored hierarchy under this DisplayContent,
+                // so SurfaceControl will write the layers of this hierarchy to the output surface
+                // provided by the app.
+                .reparent(mMirroredSurface, mSurfaceControl)
+                // Reparent the SurfaceControl of this DisplayContent to null, to prevent content
+                // being added to it. This ensures that no app launched explicitly on the
+                // VirtualDisplay will show up as part of the mirrored content.
+                .reparent(mWindowingLayer, null);
+        // Retrieve the size of the DisplayArea to mirror.
+        updateMirroredSurface(transaction, wc.getDisplayContent().getBounds());
+        mTokenToMirror = tokenToMirror;
+
+        // No need to clean up. In SurfaceFlinger, parents hold references to their children. The
+        // mirrored SurfaceControl is alive since the parent DisplayContent SurfaceControl is
+        // holding a reference to it. Therefore, the mirrored SurfaceControl will be cleaned up
+        // when the VirtualDisplay is destroyed - which will clean up this DisplayContent.
+    }
+
+    /**
+     * Start or stop mirroring if this DisplayContent now has content, or no longer has content.
+     */
+    private void updateMirroring() {
+        if (mLastHasContent && mMirroredSurface != null) {
+            // Display now has content, so stop mirroring to it.
+            mWmService.mTransactionFactory.get()
+                    // Remove the reference to mMirroredSurface, to clean up associated memory.
+                    .remove(mMirroredSurface)
+                    // Reparent the SurfaceControl of this DisplayContent back to mSurfaceControl,
+                    // to allow content to be added to it. This allows this DisplayContent to stop
+                    // mirroring and show content normally.
+                    .reparent(mWindowingLayer, mSurfaceControl).apply();
+            // Stop mirroring by destroying the reference to the mirrored layer.
+            mMirroredSurface = null;
+            // Do not un-set the token, in case content is removed and mirroring should begin again.
+        } else if (!mLastHasContent && mMirroredSurface == null) {
+            // Display no longer has content, so start mirroring to it.
+            startMirrorIfNeeded();
+        }
+    }
+
+    /**
+     * Apply transformations to the mirrored surface to ensure the captured contents are scaled to
+     * fit and centred in the output surface.
+     *
+     * @param transaction            the transaction to include transformations of mMirroredSurface
+     *                               to. Transaction is not applied before returning.
+     * @param displayAreaBounds      bounds of the DisplayArea to mirror to the surface provided by
+     *                               the app.
+     */
+    @VisibleForTesting
+    void updateMirroredSurface(SurfaceControl.Transaction transaction,
+            Rect displayAreaBounds) {
+        // Retrieve the default size of the surface the app provided to
+        // MediaProjection#createVirtualDisplay. Note the app is the consumer of the surface,
+        // since it reads out buffers from the surface, and SurfaceFlinger is the producer since
+        // it writes the mirrored layers to the buffers.
+        final Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize(
+                mDisplayId);
+
+        // Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
+        // output surface.
+        float scaleX = surfaceSize.x / (float) displayAreaBounds.width();
+        float scaleY = surfaceSize.y / (float) displayAreaBounds.height();
+        float scale = Math.min(scaleX, scaleY);
+        int scaledWidth = Math.round(scale * (float) displayAreaBounds.width());
+        int scaledHeight = Math.round(scale * (float) displayAreaBounds.height());
+
+        // Calculate the shift to apply to the root mirror SurfaceControl to centre the mirrored
+        // contents in the output surface.
+        int shiftedX = 0;
+        if (scaledWidth != surfaceSize.x) {
+            shiftedX = (surfaceSize.x - scaledWidth) / 2;
+        }
+        int shiftedY = 0;
+        if (scaledHeight != surfaceSize.y) {
+            shiftedY = (surfaceSize.y - scaledHeight) / 2;
+        }
+
+        transaction
+                // Crop the area to capture to exclude the 'extra' wallpaper that is used
+                // for parallax (b/189930234).
+                .setWindowCrop(mMirroredSurface, displayAreaBounds.width(),
+                        displayAreaBounds.height())
+                // Scale the root mirror SurfaceControl, based upon the size difference between the
+                // source (DisplayArea to capture) and output (surface the app reads images from).
+                .setMatrix(mMirroredSurface, scale, 0 /* dtdx */, 0 /* dtdy */, scale)
+                // Position needs to be updated when the mirrored DisplayArea has changed, since
+                // the content will no longer be centered in the output surface.
+                .setPosition(mMirroredSurface, shiftedX /* x */, shiftedY /* y */)
+                .apply();
+        mLastMirroredDisplayAreaBounds = new Rect(displayAreaBounds);
+    }
+
     /** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */
     class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener {
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f6317a4..04b6d47 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -125,7 +125,6 @@
 import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
 import static com.android.server.wm.TaskProto.TASK_FRAGMENT;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.TASK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
@@ -723,7 +722,7 @@
             } catch (RemoteException e) {
             }
         }
-        if (autoRemoveFromRecents() || isVoiceSession) {
+        if (autoRemoveFromRecents(oldParent.asTaskFragment()) || isVoiceSession) {
             // Task creator asked to remove this when done, or this task was a voice
             // interaction, so it should not remain on the recent tasks list.
             mTaskSupervisor.mRecentTasks.remove(this);
@@ -1513,7 +1512,7 @@
         if (DEBUG_TASK_MOVEMENT) {
             Slog.d(TAG_WM, "removeChild: child=" + r + " reason=" + reason);
         }
-        super.removeChild(r);
+        super.removeChild(r, false /* removeSelfIfPossible */);
 
         if (inPinnedWindowingMode()) {
             // We normally notify listeners of task stack changes on pause, however root pinned task
@@ -1543,7 +1542,10 @@
             // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
             // or created by task organizer.
             if (!isRootTask()) {
-                getRootTask().removeChild(this, reason);
+                final WindowContainer<?> parent = getParent();
+                if (parent != null) {
+                    parent.asTaskFragment().removeChild(this);
+                }
             }
             EventLogTags.writeWmTaskRemoved(mTaskId,
                     "removeChild:" + reason + " last r=" + r + " in t=" + this);
@@ -1575,11 +1577,12 @@
         return count > 0;
     }
 
-    private boolean autoRemoveFromRecents() {
+    private boolean autoRemoveFromRecents(TaskFragment oldParentFragment) {
         // We will automatically remove the task either if it has explicitly asked for
         // this, or it is empty and has never contained an activity that got shown to
-        // the user.
-        return autoRemoveRecents || (!hasChild() && !getHasBeenVisible());
+        // the user, or it was being embedded in another Task.
+        return autoRemoveRecents || (!hasChild() && !getHasBeenVisible()
+                || (oldParentFragment != null && oldParentFragment.isEmbedded()));
     }
 
     private void clearPinnedTaskIfNeed() {
@@ -2594,25 +2597,12 @@
         }
     }
 
-    @VisibleForTesting
-    boolean hasWindowsAlive() {
-        return getActivity(ActivityRecord::hasWindowsAlive) != null;
-    }
-
-    @VisibleForTesting
-    boolean shouldDeferRemoval() {
-        if (mChildren.isEmpty()) {
-            // No reason to defer removal of a Task that doesn't have any child.
-            return false;
-        }
-        return hasWindowsAlive() && getRootTask().isAnimating(TRANSITION | CHILDREN);
-    }
-
     @Override
     void removeImmediately() {
         removeImmediately("removeTask");
     }
 
+    @Override
     void removeImmediately(String reason) {
         if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask:" + reason + " removing taskId=" + mTaskId);
         if (mRemoving) {
@@ -3393,19 +3383,9 @@
     @Override
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         super.dump(pw, prefix, dumpAll);
-        pw.println(prefix + "bounds=" + getBounds().toShortString());
-        final String doublePrefix = prefix + "  ";
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final WindowContainer<?> child = mChildren.get(i);
-            pw.println(prefix + "* " + child);
-            // Only dump non-activity because full activity info is already printed by
-            // RootWindowContainer#dumpActivities.
-            if (child.asActivityRecord() == null) {
-                child.dump(pw, doublePrefix, dumpAll);
-            }
-        }
 
         if (!mExitingActivities.isEmpty()) {
+            final String doublePrefix = prefix + "  ";
             pw.println();
             pw.println(prefix + "Exiting application tokens:");
             for (int i = mExitingActivities.size() - 1; i >= 0; i--) {
@@ -5359,18 +5339,6 @@
         return true;
     }
 
-    /** Finish all activities in the root task without waiting. */
-    void finishAllActivitiesImmediately() {
-        if (!hasChild()) {
-            removeIfPossible("finishAllActivitiesImmediately");
-            return;
-        }
-        forAllActivities((r) -> {
-            Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r);
-            r.destroyIfPossible("finishAllActivitiesImmediately");
-        });
-    }
-
     /** @return true if the root task behind this one is a standard activity type. */
     private boolean inFrontOfStandardRootTask() {
         final TaskDisplayArea taskDisplayArea = getDisplayArea();
@@ -5766,17 +5734,14 @@
 
     @Override
     void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
-        pw.print(prefix); pw.print("* "); pw.println(this);
-        pw.println(prefix + "  mBounds=" + getRequestedOverrideBounds());
-        pw.println(prefix + "  mCreatedByOrganizer=" + mCreatedByOrganizer);
+        super.dumpInner(prefix, pw, dumpAll, dumpPackage);
+        if (mCreatedByOrganizer) {
+            pw.println(prefix + "  mCreatedByOrganizer=true");
+        }
         if (mLastNonFullscreenBounds != null) {
             pw.print(prefix); pw.print("  mLastNonFullscreenBounds=");
             pw.println(mLastNonFullscreenBounds);
         }
-        if (dumpAll) {
-            printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
-                    prefix + "  mLastPausedActivity: ", null);
-        }
         if (isLeafTask()) {
             pw.println(prefix + "  isSleeping=" + shouldSleepActivities());
             printThisActivity(pw, getTopPausingActivity(), dumpPackage, false,
@@ -6173,16 +6138,6 @@
         getDisplayContent().getPinnedTaskController().setActions(actions);
     }
 
-    /** Returns true if a removal action is still being deferred. */
-    boolean handleCompleteDeferredRemoval() {
-        if (isAnimating(TRANSITION | CHILDREN)
-                || mAtmService.getTransitionController().inTransition(this)) {
-            return true;
-        }
-
-        return super.handleCompleteDeferredRemoval();
-    }
-
     public DisplayInfo getDisplayInfo() {
         return mDisplayContent.getDisplayInfo();
     }
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 6c8cde43..cfad936 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -2104,7 +2104,7 @@
             if (destroyContentOnRemoval
                     || !task.isActivityTypeStandardOrUndefined()
                     || task.mCreatedByOrganizer) {
-                task.finishAllActivitiesImmediately();
+                task.remove(false /* withTransition */, "removeTaskDisplayArea");
             } else {
                 // Reparent task to corresponding launch root or display area.
                 final WindowContainer launchRoot =
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 5d679cf..6c31716 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -61,6 +61,8 @@
 import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
 import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
 import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
 
 import android.annotation.IntDef;
@@ -158,8 +160,8 @@
      */
     int mMinHeight;
 
-    /** Avoid reentrant of {@link #removeImmediately()}. */
-    private boolean mRemoving;
+    /** This task fragment will be removed when the cleanup of its children are done. */
+    private boolean mIsRemovalRequested;
 
     /** The TaskFragment that is adjacent to this one. */
     @Nullable
@@ -2047,15 +2049,67 @@
     }
 
     @Override
-    void removeImmediately() {
-        if (mRemoving) {
+    void removeChild(WindowContainer child) {
+        removeChild(child, true /* removeSelfIfPossible */);
+    }
+
+    void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
+        super.removeChild(child);
+        if (removeSelfIfPossible && (!mCreatedByOrganizer || mIsRemovalRequested) && !hasChild()) {
+            removeImmediately("removeLastChild " + child);
+        }
+    }
+
+    /**
+     * Requests to remove this task fragment. If it doesn't have children, it is removed
+     * immediately. Otherwise it will be removed until all activities are destroyed.
+     *
+     * @param withTransition Whether to use transition animation when removing activities. Set to
+     *                       {@code false} if this is invisible to user, e.g. display removal.
+     */
+    void remove(boolean withTransition, String reason) {
+        if (!hasChild()) {
+            removeImmediately(reason);
             return;
         }
-        mRemoving = true;
+        mIsRemovalRequested = true;
+        forAllActivities(r -> {
+            if (withTransition) {
+                r.finishIfPossible(reason, false /* oomAdj */);
+            } else {
+                r.destroyIfPossible(reason);
+            }
+        });
+    }
+
+    boolean shouldDeferRemoval() {
+        if (!hasChild()) {
+            return false;
+        }
+        return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES)
+                || mAtmService.getTransitionController().inTransition(this);
+    }
+
+    @Override
+    boolean handleCompleteDeferredRemoval() {
+        if (shouldDeferRemoval()) {
+            return true;
+        }
+        return super.handleCompleteDeferredRemoval();
+    }
+
+    /** The overridden method must call {@link #removeImmediately()} instead of super. */
+    void removeImmediately(String reason) {
+        Slog.d(TAG, "Remove task fragment: " + reason);
+        removeImmediately();
+    }
+
+    @Override
+    void removeImmediately() {
+        mIsRemovalRequested = false;
         resetAdjacentTaskFragment();
         super.removeImmediately();
         sendTaskFragmentVanished();
-        mRemoving = false;
     }
 
     boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
@@ -2083,10 +2137,10 @@
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             WindowContainer child = mChildren.get(i);
             if (child.asTaskFragment() != null) {
-                printed |= child.asTaskFragment().dump(prefix + "      ", fd, pw, dumpAll,
+                printed |= child.asTaskFragment().dump(prefix + "  ", fd, pw, dumpAll,
                         dumpClient, dumpPackage, needSep, headerPrinter);
             } else if (child.asActivityRecord() != null) {
-                ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + "      ",
+                ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + "  ",
                         "Hist ", true, !dumpAll, dumpClient, dumpPackage, false, headerPrinter,
                         getTask());
             }
@@ -2097,7 +2151,13 @@
 
     void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) {
         pw.print(prefix); pw.print("* "); pw.println(this);
-        pw.println(prefix + "  mBounds=" + getRequestedOverrideBounds());
+        final Rect bounds = getRequestedOverrideBounds();
+        if (!bounds.isEmpty()) {
+            pw.println(prefix + "  mBounds=" + bounds);
+        }
+        if (mIsRemovalRequested) {
+            pw.println(prefix + "  mIsRemovalRequested=true");
+        }
         if (dumpAll) {
             printThisActivity(pw, mLastPausedActivity, dumpPackage, false,
                     prefix + "  mLastPausedActivity: ", null);
@@ -2105,6 +2165,22 @@
     }
 
     @Override
+    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+        super.dump(pw, prefix, dumpAll);
+        pw.println(prefix + "bounds=" + getBounds().toShortString());
+        final String doublePrefix = prefix + "  ";
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowContainer<?> child = mChildren.get(i);
+            pw.println(prefix + "* " + child);
+            // Only dump non-activity because full activity info is already printed by
+            // RootWindowContainer#dumpActivities.
+            if (child.asActivityRecord() == null) {
+                child.dump(pw, doublePrefix, dumpAll);
+            }
+        }
+    }
+
+    @Override
     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(HASH_CODE, System.identityHashCode(this));
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index a322384..96860a2 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -230,11 +230,16 @@
         validateAndGetState(organizer);
         final int pid = Binder.getCallingPid();
         final long uid = Binder.getCallingUid();
-        synchronized (mGlobalLock) {
-            ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
-                    "Unregister task fragment organizer=%s uid=%d pid=%d",
-                    organizer.asBinder(), uid, pid);
-            removeOrganizer(organizer);
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+                        "Unregister task fragment organizer=%s uid=%d pid=%d",
+                        organizer.asBinder(), uid, pid);
+                removeOrganizer(organizer);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index b17a939..fa7b276 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -658,7 +658,7 @@
 
                 ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete root task display=%d winMode=%d",
                         task.getDisplayId(), task.getWindowingMode());
-                task.removeImmediately("deleteRootTask");
+                task.remove(true /* withTransition */, "deleteRootTask");
                 return true;
             }
         } finally {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index da16de7..5366bd4 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1070,6 +1070,9 @@
                 task.fillTaskInfo(tinfo);
                 change.setTaskInfo(tinfo);
                 change.setRotationAnimation(getTaskRotationAnimation(task));
+                final ActivityRecord topMostActivity = task.getTopMostActivity();
+                change.setAllowEnterPip(topMostActivity != null
+                        && topMostActivity.checkEnterPictureInPictureAppOpsState());
             }
             out.addChange(change);
         }
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 6ce4f89..aa147c4 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1182,7 +1182,7 @@
             return;
         }
         mLaunchTaskFragments.removeAt(index);
-        taskFragment.removeImmediately();
+        taskFragment.remove(true /* withTransition */, "deleteTaskFragment");
     }
 
     @Nullable
diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java
index 0ded8fb..a967ea8 100644
--- a/services/core/java/com/android/server/wm/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java
@@ -68,7 +68,7 @@
     private static final String KEY_ROTATION_MEMORIZATION_TIMEOUT =
             "rotation_memorization_timeout_millis";
     private static final long DEFAULT_ROTATION_RESOLVER_TIMEOUT_MILLIS = 700L;
-    private static final long DEFAULT_ROTATION_MEMORIZATION_TIMEOUT_MILLIS = 10_000L; // 10 seconds
+    private static final long DEFAULT_ROTATION_MEMORIZATION_TIMEOUT_MILLIS = 3_000L; // 3 seconds
 
     private Handler mHandler;
     private SensorManager mSensorManager;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 54406c2..9ca09d2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -147,6 +147,7 @@
 
 import java.util.ArrayList;
 import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 
 /**
@@ -1603,31 +1604,23 @@
     }
 
     @Test
-    public void testRemoveImmediately() throws RemoteException {
-        final ActivityRecord activity = createActivityWithTask();
-        final WindowProcessController wpc = activity.app;
-        activity.getTask().removeImmediately("test");
-
-        verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.appToken),
-                isA(DestroyActivityItem.class));
-        assertNull(activity.app);
-        assertEquals(DESTROYED, activity.getState());
-        assertFalse(wpc.hasActivities());
-    }
-
-    @Test
-    public void testRemoveImmediatelyWithFinishingActivity() throws RemoteException {
-        final ActivityRecord activity = createActivityWithTask();
-        final WindowProcessController wpc = activity.app;
-        activity.makeFinishingLocked();
-        assertTrue(activity.finishing);
-
-        activity.getTask().removeImmediately("test");
-
-        verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.appToken),
-                isA(DestroyActivityItem.class));
-        assertFalse(wpc.hasActivities());
-        assertEquals(DESTROYING, activity.getState());
+    public void testRemoveImmediately() {
+        final Consumer<Consumer<ActivityRecord>> test = setup -> {
+            final ActivityRecord activity = createActivityWithTask();
+            final WindowProcessController wpc = activity.app;
+            setup.accept(activity);
+            activity.getTask().removeImmediately("test");
+            try {
+                verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.appToken),
+                        isA(DestroyActivityItem.class));
+            } catch (RemoteException ignored) {
+            }
+            assertNull(activity.app);
+            assertEquals(DESTROYED, activity.getState());
+            assertFalse(wpc.hasActivities());
+        };
+        test.accept(activity -> activity.setState(RESUMED, "test"));
+        test.accept(activity -> activity.finishing = true);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index d086474..f3bb59c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -67,6 +67,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
@@ -107,9 +108,12 @@
 import android.app.servertransaction.FixedRotationAdjustmentsItem;
 import android.content.res.Configuration;
 import android.graphics.Insets;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.metrics.LogMaker;
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -142,6 +146,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -2220,6 +2226,113 @@
         assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
     }
 
+    @Test
+    public void testVirtualDisplayContent() {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .spyStatic(SurfaceControl.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+        // mirror.
+        final IBinder tokenToMirror = setUpDefaultTaskDisplayAreaWindowToken();
+
+        // GIVEN SurfaceControl can successfully mirror the provided surface.
+        Point surfaceSize = new Point(
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+        surfaceControlMirrors(surfaceSize);
+
+        // WHEN creating the DisplayContent for a new virtual display.
+        final DisplayContent virtualDisplay = new TestDisplayContent.Builder(mAtm,
+                mDisplayInfo).build();
+
+        // THEN mirroring is initiated for the default display's DisplayArea.
+        assertThat(virtualDisplay.mTokenToMirror).isEqualTo(tokenToMirror);
+
+        mockSession.finishMocking();
+    }
+
+    @Test
+    public void testVirtualDisplayContent_capturedAreaResized() {
+        MockitoSession mockSession = mockitoSession()
+                .initMocks(this)
+                .spyStatic(SurfaceControl.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+
+        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+        // mirror.
+        final IBinder tokenToMirror = setUpDefaultTaskDisplayAreaWindowToken();
+
+        // GIVEN SurfaceControl can successfully mirror the provided surface.
+        Point surfaceSize = new Point(
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+                mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+        SurfaceControl mirroredSurface = surfaceControlMirrors(surfaceSize);
+
+        // WHEN creating the DisplayContent for a new virtual display.
+        final DisplayContent virtualDisplay = new TestDisplayContent.Builder(mAtm,
+                mDisplayInfo).build();
+
+        // THEN mirroring is initiated for the default display's DisplayArea.
+        assertThat(virtualDisplay.mTokenToMirror).isEqualTo(tokenToMirror);
+
+        float xScale = 0.7f;
+        float yScale = 2f;
+        Rect displayAreaBounds = new Rect(0, 0, Math.round(surfaceSize.x * xScale),
+                Math.round(surfaceSize.y * yScale));
+        virtualDisplay.updateMirroredSurface(mTransaction, displayAreaBounds);
+
+        // THEN content in the captured DisplayArea is scaled to fit the surface size.
+        verify(mTransaction, atLeastOnce()).setMatrix(mirroredSurface, 1.0f / yScale, 0, 0,
+                1.0f / yScale);
+        // THEN captured content is positioned in the centre of the output surface.
+        float scaledWidth = displayAreaBounds.width() / xScale;
+        float xInset = (surfaceSize.x - scaledWidth) / 2;
+        verify(mTransaction, atLeastOnce()).setPosition(mirroredSurface, xInset, 0);
+
+        mockSession.finishMocking();
+    }
+
+    private class TestToken extends Binder {
+    }
+
+    /**
+     * Creates a WindowToken associated with the default task DisplayArea, in order for that
+     * DisplayArea to be mirrored.
+     */
+    private IBinder setUpDefaultTaskDisplayAreaWindowToken() {
+        // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+        // mirror.
+        final IBinder tokenToMirror = new TestToken();
+        doReturn(tokenToMirror).when(mWm.mDisplayManagerInternal).getWindowTokenClientToMirror(
+                anyInt());
+
+        // GIVEN the default task display area is represented by the WindowToken.
+        spyOn(mWm.mWindowContextListenerController);
+        doReturn(mDefaultDisplay.getDefaultTaskDisplayArea()).when(
+                mWm.mWindowContextListenerController).getContainer(any());
+        return tokenToMirror;
+    }
+
+    /**
+     * SurfaceControl successfully creates a mirrored surface of the given size.
+     */
+    private SurfaceControl surfaceControlMirrors(Point surfaceSize) {
+        // Do not set the parent, since the mirrored surface is the root of a new surface hierarchy.
+        SurfaceControl mirroredSurface = new SurfaceControl.Builder()
+                .setName("mirroredSurface")
+                .setBufferSize(surfaceSize.x, surfaceSize.y)
+                .setCallsite("mirrorSurface")
+                .build();
+        doReturn(mirroredSurface).when(() -> SurfaceControl.mirrorSurface(any()));
+        doReturn(surfaceSize).when(mWm.mDisplayManagerInternal).getDisplaySurfaceDefaultSize(
+                anyInt());
+        return mirroredSurface;
+    }
+
     private void removeRootTaskTests(Runnable runnable) {
         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
         final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
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 6cc60ea..56d01cd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -191,7 +191,6 @@
         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
 
         // Root task removal is deferred if one of its child is animating.
-        doReturn(true).when(rootTask).hasWindowsAlive();
         doReturn(rootTask).when(task).getAnimatingContainer(
                 eq(TRANSITION | CHILDREN), anyInt());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 629e452..8074944 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -126,8 +126,15 @@
         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
         final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
 
-        task.removeIfPossible();
-        // Assert that the container was removed.
+        task.remove(false /* withTransition */, "testRemoveContainer");
+        // There is still an activity to be destroyed, so the task is not removed immediately.
+        assertNotNull(task.getParent());
+        assertTrue(rootTask.hasChild());
+        assertTrue(task.hasChild());
+        assertTrue(activity.finishing);
+
+        activity.destroyed("testRemoveContainer");
+        // Assert that the container was removed after the activity is destroyed.
         assertNull(task.getParent());
         assertEquals(0, task.getChildCount());
         assertNull(activity.getParent());