Merge "Close guts during transitions" into sc-dev
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
index 1bd90a8..cfcb4e7 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShimPriv.apk"
   }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
index 544bca02..0948e47 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__arm_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_arm64/CtsShim.apk"
   }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
index 72386bb..db64475 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShimPriv_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShimPriv.apk"
   }
diff --git a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
index 893eac2..80812df 100644
--- a/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
+++ b/.prebuilt_info/prebuilt_info_packages_CtsShim_apk__x86_CtsShim_apk.asciipb
@@ -1,6 +1,6 @@
 drops {
   android_build_drop {
-    build_id: "7197701"
+    build_id: "7351002"
     target: "CtsShim"
     source_file: "aosp_x86_64/CtsShim.apk"
   }
diff --git a/Android.bp b/Android.bp
index d75239a..7c9cdcf 100644
--- a/Android.bp
+++ b/Android.bp
@@ -483,6 +483,19 @@
     "--api-lint-ignore-prefix junit. " +
     "--api-lint-ignore-prefix org. "
 
+packages_to_document = [
+    "android",
+    "dalvik",
+    "java",
+    "javax",
+    "junit",
+    "org.apache.http",
+    "org.json",
+    "org.w3c.dom",
+    "org.xml.sax",
+    "org.xmlpull",
+]
+
 filegroup {
     name: "android-non-updatable-stub-sources",
     srcs: [
@@ -535,7 +548,7 @@
         "android.hardware.usb.gadget-V1.0-java",
         "android.hardware.vibrator-V1.3-java",
         "framework-protos",
-        "stable.core.platform.api.stubs",
+        "art.module.public.api",
         // There are a few classes from modules used by the core that
         // need to be resolved by metalava. We use a prebuilt stub of the
         // full sdk to ensure we can resolve them. If a new class gets added,
@@ -544,6 +557,7 @@
         // NOTE: The below can be removed once the prebuilt stub contains IKE.
         "sdk_system_current_android.net.ipsec.ike",
     ],
+    filter_packages: packages_to_document,
     high_mem: true, // Lots of sources => high memory use, see b/170701554
     installable: false,
     annotations_enabled: true,
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 0f218b5..0aed5d9 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -93,13 +93,14 @@
         ":updatable-media-srcs",
 
         // No longer part of the stubs, but are included in the docs.
-        "test-base/src/**/*.java",
-        "test-mock/src/**/*.java",
-        "test-runner/src/**/*.java",
+        ":android-test-base-sources",
+        ":android-test-mock-sources",
+        ":android-test-runner-sources",
     ],
     libs: framework_docs_only_libs,
     create_doc_stubs: true,
     annotations_enabled: true,
+    filter_packages: packages_to_document,
     api_levels_annotations_enabled: true,
     api_levels_annotations_dirs: [
         "sdk-dir",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 7b8a687..ed24d43 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -27,24 +27,10 @@
 // Common metalava configs
 /////////////////////////////////////////////////////////////////////
 
-packages_to_document = [
-    "android",
-    "dalvik",
-    "java",
-    "javax",
-    "junit",
-    "org.apache.http",
-    "org.json",
-    "org.w3c.dom",
-    "org.xml.sax",
-    "org.xmlpull",
-]
-
 stubs_defaults {
     name: "metalava-non-updatable-api-stubs-default",
     defaults: ["android-non-updatable-stubs-defaults"],
     api_levels_annotations_enabled: false,
-    filter_packages: packages_to_document,
     defaults_visibility: ["//visibility:private"],
 }
 
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index 4dff436..5a2f702 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -290,14 +290,12 @@
     method @NonNull public String getDatabaseName();
     method @NonNull public android.app.appsearch.GenericDocument getGenericDocument();
     method @NonNull public java.util.List<android.app.appsearch.SearchResult.MatchInfo> getMatchInfos();
-    method @Deprecated @NonNull public java.util.List<android.app.appsearch.SearchResult.MatchInfo> getMatches();
     method @NonNull public String getPackageName();
     method public double getRankingSignal();
   }
 
   public static final class SearchResult.Builder {
     ctor public SearchResult.Builder(@NonNull String, @NonNull String);
-    method @Deprecated @NonNull public android.app.appsearch.SearchResult.Builder addMatch(@NonNull android.app.appsearch.SearchResult.MatchInfo);
     method @NonNull public android.app.appsearch.SearchResult.Builder addMatchInfo(@NonNull android.app.appsearch.SearchResult.MatchInfo);
     method @NonNull public android.app.appsearch.SearchResult build();
     method @NonNull public android.app.appsearch.SearchResult.Builder setGenericDocument(@NonNull android.app.appsearch.GenericDocument);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.aidl b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.aidl
deleted file mode 100644
index 4686de8..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright 2020, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.appsearch;
-
-/** {@hide} */
-parcelable AppSearchBatchResult;
\ No newline at end of file
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index c4dd1a0..bc3c79f 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -18,6 +18,7 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.SystemService;
+import android.app.appsearch.aidl.IAppSearchManager;
 import android.content.Context;
 
 import com.android.internal.util.Preconditions;
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
index ec0533e..7dc527a 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java
@@ -17,6 +17,7 @@
 
 import android.annotation.SystemApi;
 import android.app.SystemServiceRegistry;
+import android.app.appsearch.aidl.IAppSearchManager;
 import android.content.Context;
 
 /**
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java
index 0089c6d..353051c 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchMigrationHelper.java
@@ -23,6 +23,9 @@
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
+import android.app.appsearch.aidl.AppSearchResultParcel;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -105,8 +108,8 @@
                     mUserId,
                     new IAppSearchResultCallback.Stub() {
                         @Override
-                        public void onResult(AppSearchResult result) {
-                            future.complete(result);
+                        public void onResult(AppSearchResultParcel resultParcel) {
+                            future.complete(resultParcel.getResult());
                         }
                     });
             AppSearchResult<Void> result = future.get();
@@ -145,8 +148,8 @@
             mService.putDocumentsFromFile(mPackageName, mDatabaseName, fileDescriptor, mUserId,
                     new IAppSearchResultCallback.Stub() {
                         @Override
-                        public void onResult(AppSearchResult result) {
-                            future.complete(result);
+                        public void onResult(AppSearchResultParcel resultParcel) {
+                            future.complete(resultParcel.getResult());
                         }
                     });
             AppSearchResult<List<Bundle>> result = future.get();
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index c112d0e..5910130 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -19,6 +19,11 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
+import android.app.appsearch.aidl.AppSearchBatchResultParcel;
+import android.app.appsearch.aidl.AppSearchResultParcel;
+import android.app.appsearch.aidl.IAppSearchBatchResultCallback;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.app.appsearch.util.SchemaMigrationUtil;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -86,13 +91,15 @@
             @NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
         try {
             mService.initialize(mUserId, new IAppSearchResultCallback.Stub() {
-                public void onResult(AppSearchResult result) {
+                @Override
+                public void onResult(AppSearchResultParcel resultParcel) {
                     executor.execute(() -> {
+                        AppSearchResult<Void> result = resultParcel.getResult();
                         if (result.isSuccess()) {
                             callback.accept(
                                     AppSearchResult.newSuccessfulResult(AppSearchSession.this));
                         } else {
-                            callback.accept(result);
+                            callback.accept(AppSearchResult.newFailedResult(result));
                         }
                     });
                 }
@@ -191,15 +198,16 @@
                     mDatabaseName,
                     mUserId,
                     new IAppSearchResultCallback.Stub() {
-                        public void onResult(AppSearchResult result) {
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
                             executor.execute(() -> {
+                                AppSearchResult<Bundle> result = resultParcel.getResult();
                                 if (result.isSuccess()) {
-                                    Bundle responseBundle = (Bundle) result.getResultValue();
                                     GetSchemaResponse response =
-                                            new GetSchemaResponse(responseBundle);
+                                            new GetSchemaResponse(result.getResultValue());
                                     callback.accept(AppSearchResult.newSuccessfulResult(response));
                                 } else {
-                                    callback.accept(result);
+                                    callback.accept(AppSearchResult.newFailedResult(result));
                                 }
                             });
                         }
@@ -227,15 +235,17 @@
                     mDatabaseName,
                     mUserId,
                     new IAppSearchResultCallback.Stub() {
-                        public void onResult(AppSearchResult result) {
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
                             executor.execute(() -> {
+                                AppSearchResult<List<String>> result = resultParcel.getResult();
                                 if (result.isSuccess()) {
                                     Set<String> namespaces =
-                                            new ArraySet<>((List<String>) result.getResultValue());
+                                            new ArraySet<>(result.getResultValue());
                                     callback.accept(
                                             AppSearchResult.newSuccessfulResult(namespaces));
                                 } else {
-                                    callback.accept(result);
+                                    callback.accept(AppSearchResult.newFailedResult(result));
                                 }
                             });
                         }
@@ -280,13 +290,14 @@
                     /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime(),
                     new IAppSearchBatchResultCallback.Stub() {
                         @Override
-                        public void onResult(AppSearchBatchResult result) {
-                            executor.execute(() -> callback.onResult(result));
+                        public void onResult(AppSearchBatchResultParcel resultParcel) {
+                            executor.execute(() -> callback.onResult(resultParcel.getResult()));
                         }
 
                         @Override
-                        public void onSystemError(AppSearchResult result) {
-                            executor.execute(() -> sendSystemErrorToCallback(result, callback));
+                        public void onSystemError(AppSearchResultParcel resultParcel) {
+                            executor.execute(() -> sendSystemErrorToCallback(
+                                    resultParcel.getResult(), callback));
                         }
                     });
             mIsMutated = true;
@@ -341,15 +352,17 @@
                     mUserId,
                     new IAppSearchBatchResultCallback.Stub() {
                         @Override
-                        public void onResult(AppSearchBatchResult result) {
+                        public void onResult(AppSearchBatchResultParcel resultParcel) {
                             executor.execute(() -> {
+                                AppSearchBatchResult<String, Bundle> result =
+                                        resultParcel.getResult();
                                 AppSearchBatchResult.Builder<String, GenericDocument>
                                         documentResultBuilder =
                                         new AppSearchBatchResult.Builder<>();
 
                                 // Translate successful results
                                 for (Map.Entry<String, Bundle> bundleEntry :
-                                        ((Map<String, Bundle>) result.getSuccesses()).entrySet()) {
+                                        result.getSuccesses().entrySet()) {
                                     GenericDocument document;
                                     try {
                                         document = new GenericDocument(bundleEntry.getValue());
@@ -380,8 +393,9 @@
                         }
 
                         @Override
-                        public void onSystemError(AppSearchResult result) {
-                            executor.execute(() -> sendSystemErrorToCallback(result, callback));
+                        public void onSystemError(AppSearchResultParcel result) {
+                            executor.execute(
+                                    () -> sendSystemErrorToCallback(result.getResult(), callback));
                         }
                     });
         } catch (RemoteException e) {
@@ -492,8 +506,9 @@
                     /*systemUsage=*/ false,
                     mUserId,
                     new IAppSearchResultCallback.Stub() {
-                        public void onResult(AppSearchResult result) {
-                            executor.execute(() -> callback.accept(result));
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
+                            executor.execute(() -> callback.accept(resultParcel.getResult()));
                         }
                     });
             mIsMutated = true;
@@ -550,13 +565,14 @@
                     new ArrayList<>(request.getIds()), mUserId,
                     new IAppSearchBatchResultCallback.Stub() {
                         @Override
-                        public void onResult(AppSearchBatchResult result) {
-                            executor.execute(() -> callback.onResult(result));
+                        public void onResult(AppSearchBatchResultParcel resultParcel) {
+                            executor.execute(() -> callback.onResult(resultParcel.getResult()));
                         }
 
                         @Override
-                        public void onSystemError(AppSearchResult result) {
-                            executor.execute(() -> sendSystemErrorToCallback(result, callback));
+                        public void onSystemError(AppSearchResultParcel resultParcel) {
+                            executor.execute(() -> sendSystemErrorToCallback(
+                                    resultParcel.getResult(), callback));
                         }
                     });
             mIsMutated = true;
@@ -598,8 +614,9 @@
             mService.removeByQuery(mPackageName, mDatabaseName, queryExpression,
                     searchSpec.getBundle(), mUserId,
                     new IAppSearchResultCallback.Stub() {
-                        public void onResult(AppSearchResult result) {
-                            executor.execute(() -> callback.accept(result));
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
+                            executor.execute(() -> callback.accept(resultParcel.getResult()));
                         }
                     });
             mIsMutated = true;
@@ -629,15 +646,15 @@
                     mDatabaseName,
                     mUserId,
                     new IAppSearchResultCallback.Stub() {
-                        public void onResult(AppSearchResult result) {
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
                             executor.execute(() -> {
+                                AppSearchResult<Bundle> result = resultParcel.getResult();
                                 if (result.isSuccess()) {
-                                    Bundle responseBundle = (Bundle) result.getResultValue();
-                                    StorageInfo response =
-                                            new StorageInfo(responseBundle);
+                                    StorageInfo response = new StorageInfo(result.getResultValue());
                                     callback.accept(AppSearchResult.newSuccessfulResult(response));
                                 } else {
-                                    callback.accept(result);
+                                    callback.accept(AppSearchResult.newFailedResult(result));
                                 }
                             });
                         }
@@ -686,13 +703,14 @@
                     request.getVersion(),
                     mUserId,
                     new IAppSearchResultCallback.Stub() {
-                        public void onResult(AppSearchResult result) {
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
                             executor.execute(() -> {
+                                AppSearchResult<Bundle> result = resultParcel.getResult();
                                 if (result.isSuccess()) {
                                     try {
                                         SetSchemaResponse setSchemaResponse =
-                                                new SetSchemaResponse(
-                                                        (Bundle) result.getResultValue());
+                                                new SetSchemaResponse(result.getResultValue());
                                         if (!request.isForceOverride()) {
                                             // Throw exception if there is any deleted types or
                                             // incompatible types. That's the only case we swallowed
@@ -707,7 +725,7 @@
                                         callback.accept(AppSearchResult.throwableToFailedResult(t));
                                     }
                                 } else {
-                                    callback.accept(result);
+                                    callback.accept(AppSearchResult.newFailedResult(result));
                                 }
                             });
                         }
@@ -772,8 +790,9 @@
                         request.getVersion(),
                         mUserId,
                         new IAppSearchResultCallback.Stub() {
-                            public void onResult(AppSearchResult result) {
-                                setSchemaFuture.complete(result);
+                            @Override
+                            public void onResult(AppSearchResultParcel resultParcel) {
+                                setSchemaFuture.complete(resultParcel.getResult());
                             }
                         });
                 AppSearchResult<Bundle> setSchemaResult = setSchemaFuture.get();
@@ -823,8 +842,8 @@
                                 mUserId,
                                 new IAppSearchResultCallback.Stub() {
                                     @Override
-                                    public void onResult(AppSearchResult result) {
-                                        setSchema2Future.complete(result);
+                                    public void onResult(AppSearchResultParcel resultParcel) {
+                                        setSchema2Future.complete(resultParcel.getResult());
                                     }
                                 });
                         AppSearchResult<Bundle> setSchema2Result = setSchema2Future.get();
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
index d49f472..7d246c2 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -16,10 +16,12 @@
 
 package android.app.appsearch;
 
-
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
+import android.app.appsearch.aidl.AppSearchResultParcel;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -71,13 +73,15 @@
             @NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
         try {
             mService.initialize(mUserId, new IAppSearchResultCallback.Stub() {
-                public void onResult(AppSearchResult result) {
+                @Override
+                public void onResult(AppSearchResultParcel resultParcel) {
                     executor.execute(() -> {
+                        AppSearchResult<Void> result = resultParcel.getResult();
                         if (result.isSuccess()) {
                             callback.accept(
                                     AppSearchResult.newSuccessfulResult(GlobalSearchSession.this));
                         } else {
-                            callback.accept(result);
+                            callback.accept(AppSearchResult.newFailedResult(result));
                         }
                     });
                 }
@@ -159,8 +163,9 @@
                     /*systemUsage=*/ true,
                     mUserId,
                     new IAppSearchResultCallback.Stub() {
-                        public void onResult(AppSearchResult result) {
-                            executor.execute(() -> callback.accept(result));
+                        @Override
+                        public void onResult(AppSearchResultParcel resultParcel) {
+                            executor.execute(() -> callback.accept(resultParcel.getResult()));
                         }
                     });
             mIsMutated = true;
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index 531c984..4368672 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -20,6 +20,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.appsearch.aidl.AppSearchResultParcel;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Log;
@@ -139,18 +142,20 @@
             @NonNull @CallbackExecutor Executor executor,
             @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
         return new IAppSearchResultCallback.Stub() {
-            public void onResult(AppSearchResult result) {
-                executor.execute(() -> invokeCallback(result, callback));
+            @Override
+            public void onResult(AppSearchResultParcel resultParcel) {
+                executor.execute(() -> invokeCallback(resultParcel.getResult(), callback));
             }
         };
     }
 
-    private void invokeCallback(AppSearchResult result,
+    private void invokeCallback(
+            @NonNull AppSearchResult<Bundle> searchResultPageResult,
             @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
-        if (result.isSuccess()) {
+        if (searchResultPageResult.isSuccess()) {
             try {
                 SearchResultPage searchResultPage =
-                        new SearchResultPage((Bundle) result.getResultValue());
+                        new SearchResultPage(searchResultPageResult.getResultValue());
                 mNextPageToken = searchResultPage.getNextPageToken();
                 callback.accept(AppSearchResult.newSuccessfulResult(
                         searchResultPage.getResults()));
@@ -158,7 +163,7 @@
                 callback.accept(AppSearchResult.throwableToFailedResult(t));
             }
         } else {
-            callback.accept(result);
+            callback.accept(AppSearchResult.newFailedResult(searchResultPageResult));
         }
     }
 }
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl b/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchBatchResultParcel.aidl
similarity index 80%
copy from apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
copy to apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchBatchResultParcel.aidl
index 37ce990..89908cd 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchBatchResultParcel.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright 2020, The Android Open Source Project
+ * Copyright 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.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.app.appsearch.aidl;
 
 /** {@hide} */
-parcelable AppSearchResult<ValueType>;
\ No newline at end of file
+parcelable AppSearchBatchResultParcel<ValueType>;
diff --git a/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchBatchResultParcel.java b/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchBatchResultParcel.java
new file mode 100644
index 0000000..b0cc10c
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchBatchResultParcel.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.aidl;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchBatchResult;
+import android.app.appsearch.AppSearchResult;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Parcelable wrapper around {@link AppSearchBatchResult}.
+ *
+ * <p>{@link AppSearchBatchResult} can contain any type of key and value, including non-parcelable
+ * values. For the specific case of sending {@link AppSearchBatchResult} across Binder, this class
+ * wraps an {@link AppSearchBatchResult} that has String keys and Parcelable values. It provides
+ * parcelability of the whole structure.
+ *
+ * @param <ValueType> The type of result object for successful calls. Must be a parcelable type.
+ * @hide
+ */
+public final class AppSearchBatchResultParcel<ValueType> implements Parcelable {
+    private final AppSearchBatchResult<String, ValueType> mResult;
+
+    /** Creates a new {@link AppSearchBatchResultParcel} from the given result. */
+    public AppSearchBatchResultParcel(@NonNull AppSearchBatchResult<String, ValueType> result) {
+        mResult = Objects.requireNonNull(result);
+    }
+
+    private AppSearchBatchResultParcel(@NonNull Parcel in) {
+        Bundle bundle = in.readBundle();
+        AppSearchBatchResult.Builder<String, ValueType> builder =
+                new AppSearchBatchResult.Builder<>();
+        for (String key : bundle.keySet()) {
+            AppSearchResultParcel<ValueType> resultParcel = bundle.getParcelable(key);
+            builder.setResult(key, resultParcel.getResult());
+        }
+        mResult = builder.build();
+    }
+
+    @NonNull
+    public AppSearchBatchResult<String, ValueType> getResult() {
+        return mResult;
+    }
+
+    /** @hide */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        Bundle bundle = new Bundle();
+        for (Map.Entry<String, AppSearchResult<ValueType>> entry
+                : mResult.getAll().entrySet()) {
+            bundle.putParcelable(entry.getKey(), new AppSearchResultParcel<>(entry.getValue()));
+        }
+        dest.writeBundle(bundle);
+    }
+
+    /** @hide */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @NonNull
+    public static final Creator<AppSearchBatchResultParcel<?>> CREATOR =
+            new Creator<AppSearchBatchResultParcel<?>>() {
+                @NonNull
+                @Override
+                public AppSearchBatchResultParcel<?> createFromParcel(@NonNull Parcel in) {
+                    return new AppSearchBatchResultParcel<>(in);
+                }
+
+                @NonNull
+                @Override
+                public AppSearchBatchResultParcel<?>[] newArray(int size) {
+                    return new AppSearchBatchResultParcel<?>[size];
+                }
+            };
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl b/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchResultParcel.aidl
similarity index 81%
rename from apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
rename to apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchResultParcel.aidl
index 37ce990..4e35bd5 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchResultParcel.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright 2020, The Android Open Source Project
+ * Copyright 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.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.app.appsearch.aidl;
 
 /** {@hide} */
-parcelable AppSearchResult<ValueType>;
\ No newline at end of file
+parcelable AppSearchResultParcel<ValueType>;
diff --git a/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchResultParcel.java b/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchResultParcel.java
new file mode 100644
index 0000000..8b137d3
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/AppSearchResultParcel.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.aidl;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Parcelable wrapper around {@link AppSearchResult}.
+ *
+ * <p>{@link AppSearchResult} can contain any value, including non-parcelable values. For the
+ * specific case of sending {@link AppSearchResult} across Binder, this class wraps an
+ * {@link AppSearchResult} that contains a parcelable type and provides parcelability of the whole
+ * structure.
+ *
+ * @param <ValueType> The type of result object for successful calls. Must be a parcelable type.
+ * @hide
+ */
+public final class AppSearchResultParcel<ValueType> implements Parcelable {
+    private final AppSearchResult<ValueType> mResult;
+
+    /** Creates a new {@link AppSearchResultParcel} from the given result. */
+    public AppSearchResultParcel(@NonNull AppSearchResult<ValueType> result) {
+        mResult = Objects.requireNonNull(result);
+    }
+
+    private AppSearchResultParcel(@NonNull Parcel in) {
+        int resultCode = in.readInt();
+        ValueType resultValue = (ValueType) in.readValue(/*loader=*/ null);
+        String errorMessage = in.readString();
+        if (resultCode == AppSearchResult.RESULT_OK) {
+            mResult = AppSearchResult.newSuccessfulResult(resultValue);
+        } else {
+            mResult = AppSearchResult.newFailedResult(resultCode, errorMessage);
+        }
+    }
+
+    @NonNull
+    public AppSearchResult<ValueType> getResult() {
+        return mResult;
+    }
+
+    /** @hide */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mResult.getResultCode());
+        if (mResult.isSuccess()) {
+            dest.writeValue(mResult.getResultValue());
+        } else {
+            dest.writeValue(null);
+        }
+        dest.writeString(mResult.getErrorMessage());
+    }
+
+    /** @hide */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** @hide */
+    @NonNull
+    public static final Creator<AppSearchResultParcel<?>> CREATOR =
+            new Creator<AppSearchResultParcel<?>>() {
+                @NonNull
+                @Override
+                public AppSearchResultParcel<?> createFromParcel(@NonNull Parcel in) {
+                    return new AppSearchResultParcel<>(in);
+                }
+
+                @NonNull
+                @Override
+                public AppSearchResultParcel<?>[] newArray(int size) {
+                    return new AppSearchResultParcel<?>[size];
+                }
+            };
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchBatchResultCallback.aidl
similarity index 70%
rename from apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl
rename to apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchBatchResultCallback.aidl
index 64b331e..1fe19cc 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchBatchResultCallback.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchBatchResultCallback.aidl
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.app.appsearch.aidl;
 
-import android.app.appsearch.AppSearchBatchResult;
-import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.aidl.AppSearchBatchResultParcel;
+import android.app.appsearch.aidl.AppSearchResultParcel;
 
 /** {@hide} */
 oneway interface IAppSearchBatchResultCallback {
-    void onResult(in AppSearchBatchResult result);
-    void onSystemError(in AppSearchResult result);
+    void onResult(in AppSearchBatchResultParcel resultParcel);
+    void onSystemError(in AppSearchResultParcel resultParcel);
 }
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
similarity index 98%
rename from apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
rename to apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
index 507bd68..6f7e82e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
@@ -13,12 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.app.appsearch.aidl;
 
 import android.os.Bundle;
 
-import android.app.appsearch.IAppSearchBatchResultCallback;
-import android.app.appsearch.IAppSearchResultCallback;
+import android.app.appsearch.aidl.IAppSearchBatchResultCallback;
+import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.os.ParcelFileDescriptor;
 
 /** {@hide} */
@@ -200,7 +200,7 @@
     * @param searchSpecBundle SearchSpec bundle.
     * @param userId Id of the calling user.
     * @param callback {@link IAppSearchResultCallback#onResult} will be called with an
-    *        {@link AppSearchResult}&lt;{@code null}&gt;.
+    *        {@link AppSearchResult}&lt;{@code Void}&gt;.
     */
     void writeQueryResultsToFile(
         in String packageName,
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchResultCallback.aidl
similarity index 81%
rename from apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
rename to apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchResultCallback.aidl
index 299c9957..097f0d1 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchResultCallback.aidl
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.app.appsearch.aidl;
 
-import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.aidl.AppSearchResultParcel;
 
 /** {@hide} */
 oneway interface IAppSearchResultCallback {
-    void onResult(in AppSearchResult result);
+    void onResult(in AppSearchResultParcel resultParcel);
 }
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
similarity index 63%
rename from apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
rename to apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
index 9ae0d62..f0b04fc 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
@@ -13,37 +13,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.app.appsearch;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.util.ArrayMap;
 
-import com.android.internal.util.Preconditions;
-
-import java.util.Collections;
 import java.util.Map;
 import java.util.Objects;
 
 /**
  * Provides results for AppSearch batch operations which encompass multiple documents.
  *
- * <p>Individual results of a batch operation are separated into two maps: one for successes and
- * one for failures. For successes, {@link #getSuccesses()} will return a map of keys to
- * instances of the value type. For failures, {@link #getFailures()} will return a map of keys to
- * {@link AppSearchResult} objects.
+ * <p>Individual results of a batch operation are separated into two maps: one for successes and one
+ * for failures. For successes, {@link #getSuccesses()} will return a map of keys to instances of
+ * the value type. For failures, {@link #getFailures()} will return a map of keys to {@link
+ * AppSearchResult} objects.
  *
  * <p>Alternatively, {@link #getAll()} returns a map of keys to {@link AppSearchResult} objects for
  * both successes and failures.
  *
+ * @param <KeyType> The type of the keys for which the results will be reported.
+ * @param <ValueType> The type of the result objects for successful results.
  * @see AppSearchSession#put
  * @see AppSearchSession#getByDocumentId
  * @see AppSearchSession#remove
  */
-public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
+public final class AppSearchBatchResult<KeyType, ValueType> {
     @NonNull private final Map<KeyType, ValueType> mSuccesses;
     @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mFailures;
     @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mAll;
@@ -57,27 +53,6 @@
         mAll = all;
     }
 
-    private AppSearchBatchResult(@NonNull Parcel in) {
-        mAll = Collections.unmodifiableMap(in.readHashMap(/*loader=*/ null));
-        Map<KeyType, ValueType> successes = new ArrayMap<>();
-        Map<KeyType, AppSearchResult<ValueType>> failures = new ArrayMap<>();
-        for (Map.Entry<KeyType, AppSearchResult<ValueType>> entry : mAll.entrySet()) {
-            if (entry.getValue().isSuccess()) {
-                successes.put(entry.getKey(), entry.getValue().getResultValue());
-            } else {
-                failures.put(entry.getKey(), entry.getValue());
-            }
-        }
-        mSuccesses = Collections.unmodifiableMap(successes);
-        mFailures = Collections.unmodifiableMap(failures);
-    }
-
-    /** @hide */
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeMap(mAll);
-    }
-
     /** Returns {@code true} if this {@link AppSearchBatchResult} has no failures. */
     public boolean isSuccess() {
         return mFailures.isEmpty();
@@ -99,8 +74,8 @@
     }
 
     /**
-     * Returns a {@link Map} of keys mapped to instances of {@link AppSearchResult} for all
-     * failed individual results.
+     * Returns a {@link Map} of keys mapped to instances of {@link AppSearchResult} for all failed
+     * individual results.
      *
      * <p>The values of the {@link Map} will not be {@code null}.
      */
@@ -122,6 +97,7 @@
 
     /**
      * Asserts that this {@link AppSearchBatchResult} has no failures.
+     *
      * @hide
      */
     public void checkSuccess() {
@@ -136,53 +112,29 @@
         return "{\n  successes: " + mSuccesses + "\n  failures: " + mFailures + "\n}";
     }
 
-    /** @hide */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** @hide */
-    @NonNull
-    public static final Creator<AppSearchBatchResult> CREATOR =
-            new Creator<AppSearchBatchResult>() {
-        @NonNull
-        @Override
-        public AppSearchBatchResult createFromParcel(@NonNull Parcel in) {
-            return new AppSearchBatchResult(in);
-        }
-
-        @NonNull
-        @Override
-        public AppSearchBatchResult[] newArray(int size) {
-            return new AppSearchBatchResult[size];
-        }
-    };
-
     /**
      * Builder for {@link AppSearchBatchResult} objects.
      *
-     * <p>Once {@link #build} is called, the instance can no longer be used.
+     * @param <KeyType> The type of the keys for which the results will be reported.
+     * @param <ValueType> The type of the result objects for successful results.
      */
     public static final class Builder<KeyType, ValueType> {
-        private final Map<KeyType, ValueType> mSuccesses = new ArrayMap<>();
-        private final Map<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>();
-        private final Map<KeyType, AppSearchResult<ValueType>> mAll = new ArrayMap<>();
+        private ArrayMap<KeyType, ValueType> mSuccesses = new ArrayMap<>();
+        private ArrayMap<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>();
+        private ArrayMap<KeyType, AppSearchResult<ValueType>> mAll = new ArrayMap<>();
         private boolean mBuilt = false;
 
         /**
          * Associates the {@code key} with the provided successful return value.
          *
          * <p>Any previous mapping for a key, whether success or failure, is deleted.
-         *
-         * @throws IllegalStateException if the builder has already been used.
          */
-        @SuppressWarnings("MissingGetterMatchingBuilder")  // See getSuccesses
+        @SuppressWarnings("MissingGetterMatchingBuilder") // See getSuccesses
         @NonNull
         public Builder<KeyType, ValueType> setSuccess(
                 @NonNull KeyType key, @Nullable ValueType result) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(key);
+            resetIfBuilt();
             return setResult(key, AppSearchResult.newSuccessfulResult(result));
         }
 
@@ -190,17 +142,15 @@
          * Associates the {@code key} with the provided failure code and error message.
          *
          * <p>Any previous mapping for a key, whether success or failure, is deleted.
-         *
-         * @throws IllegalStateException if the builder has already been used.
          */
-        @SuppressWarnings("MissingGetterMatchingBuilder")  // See getFailures
+        @SuppressWarnings("MissingGetterMatchingBuilder") // See getFailures
         @NonNull
         public Builder<KeyType, ValueType> setFailure(
                 @NonNull KeyType key,
                 @AppSearchResult.ResultCode int resultCode,
                 @Nullable String errorMessage) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(key);
+            resetIfBuilt();
             return setResult(key, AppSearchResult.newFailedResult(resultCode, errorMessage));
         }
 
@@ -208,16 +158,14 @@
          * Associates the {@code key} with the provided {@code result}.
          *
          * <p>Any previous mapping for a key, whether success or failure, is deleted.
-         *
-         * @throws IllegalStateException if the builder has already been used.
          */
-        @SuppressWarnings("MissingGetterMatchingBuilder")  // See getAll
+        @SuppressWarnings("MissingGetterMatchingBuilder") // See getAll
         @NonNull
         public Builder<KeyType, ValueType> setResult(
                 @NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(key);
             Objects.requireNonNull(result);
+            resetIfBuilt();
             if (result.isSuccess()) {
                 mSuccesses.put(key, result.getResultValue());
                 mFailures.remove(key);
@@ -231,14 +179,21 @@
 
         /**
          * Builds an {@link AppSearchBatchResult} object from the contents of this {@link Builder}.
-         *
-         * @throws IllegalStateException if the builder has already been used.
          */
         @NonNull
         public AppSearchBatchResult<KeyType, ValueType> build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             mBuilt = true;
-            return new AppSearchBatchResult<>(mSuccesses, mFailures, mAll);
+            return new AppSearchBatchResult<>(
+                    new ArrayMap<>(mSuccesses), new ArrayMap<>(mFailures), new ArrayMap<>(mAll));
+        }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                mSuccesses = new ArrayMap<>(mSuccesses);
+                mFailures = new ArrayMap<>(mFailures);
+                mAll = new ArrayMap<>(mAll);
+                mBuilt = false;
+            }
         }
     }
 }
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java
similarity index 82%
rename from apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
rename to apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java
index b06e215..30c98b0 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java
@@ -13,15 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.app.appsearch;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.appsearch.exceptions.AppSearchException;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.util.Log;
 
 import com.android.internal.util.Preconditions;
@@ -36,24 +33,26 @@
  *
  * @param <ValueType> The type of result object for successful calls.
  */
-public final class AppSearchResult<ValueType> implements Parcelable {
+public final class AppSearchResult<ValueType> {
     private static final String TAG = "AppSearchResult";
 
     /**
      * Result codes from {@link AppSearchSession} methods.
+     *
      * @hide
      */
-    @IntDef(value = {
-            RESULT_OK,
-            RESULT_UNKNOWN_ERROR,
-            RESULT_INTERNAL_ERROR,
-            RESULT_INVALID_ARGUMENT,
-            RESULT_IO_ERROR,
-            RESULT_OUT_OF_SPACE,
-            RESULT_NOT_FOUND,
-            RESULT_INVALID_SCHEMA,
-            RESULT_SECURITY_ERROR,
-    })
+    @IntDef(
+            value = {
+                RESULT_OK,
+                RESULT_UNKNOWN_ERROR,
+                RESULT_INTERNAL_ERROR,
+                RESULT_INVALID_ARGUMENT,
+                RESULT_IO_ERROR,
+                RESULT_OUT_OF_SPACE,
+                RESULT_NOT_FOUND,
+                RESULT_INVALID_SCHEMA,
+                RESULT_SECURITY_ERROR,
+            })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ResultCode {}
 
@@ -109,20 +108,6 @@
         mErrorMessage = errorMessage;
     }
 
-    private AppSearchResult(@NonNull Parcel in) {
-        mResultCode = in.readInt();
-        mResultValue = (ValueType) in.readValue(/*loader=*/ null);
-        mErrorMessage = in.readString();
-    }
-
-    /** @hide */
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mResultCode);
-        dest.writeValue(mResultValue);
-        dest.writeString(mErrorMessage);
-    }
-
     /** Returns {@code true} if {@link #getResultCode} equals {@link AppSearchResult#RESULT_OK}. */
     public boolean isSuccess() {
         return getResultCode() == RESULT_OK;
@@ -154,8 +139,8 @@
      *
      * <p>If {@link #isSuccess} is {@code true}, the error message is always {@code null}. The error
      * message may be {@code null} even if {@link #isSuccess} is {@code false}. See the
-     * documentation of the particular {@link AppSearchSession} call producing this
-     * {@link AppSearchResult} for what is returned by {@link #getErrorMessage}.
+     * documentation of the particular {@link AppSearchSession} call producing this {@link
+     * AppSearchResult} for what is returned by {@link #getErrorMessage}.
      */
     @Nullable
     public String getErrorMessage() {
@@ -190,40 +175,14 @@
         return "[FAILURE(" + mResultCode + ")]: " + mErrorMessage;
     }
 
-    /** @hide */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** @hide */
-    @NonNull
-    public static final Creator<AppSearchResult> CREATOR = new Creator<AppSearchResult>() {
-        @NonNull
-        @Override
-        public AppSearchResult createFromParcel(@NonNull Parcel in) {
-            return new AppSearchResult(in);
-        }
-
-        @NonNull
-        @Override
-        public AppSearchResult[] newArray(int size) {
-            return new AppSearchResult[size];
-        }
-    };
-
-    /**
-     * Creates a new successful {@link AppSearchResult}.
-     */
+    /** Creates a new successful {@link AppSearchResult}. */
     @NonNull
     public static <ValueType> AppSearchResult<ValueType> newSuccessfulResult(
             @Nullable ValueType value) {
         return new AppSearchResult<>(RESULT_OK, value, /*errorMessage=*/ null);
     }
 
-    /**
-     * Creates a new failed {@link AppSearchResult}.
-     */
+    /** Creates a new failed {@link AppSearchResult}. */
     @NonNull
     public static <ValueType> AppSearchResult<ValueType> newFailedResult(
             @ResultCode int resultCode, @Nullable String errorMessage) {
@@ -238,7 +197,8 @@
     @NonNull
     public static <ValueType> AppSearchResult<ValueType> newFailedResult(
             @NonNull AppSearchResult<?> otherFailedResult) {
-        Preconditions.checkState(!otherFailedResult.isSuccess(),
+        Preconditions.checkState(
+                !otherFailedResult.isSuccess(),
                 "Cannot convert a success result to a failed result");
         return AppSearchResult.newFailedResult(
                 otherFailedResult.getResultCode(), otherFailedResult.getErrorMessage());
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
index 4378a98..c1fcd6c 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -120,7 +120,7 @@
     /** Builder for {@link AppSearchSchema objects}. */
     public static final class Builder {
         private final String mSchemaType;
-        private final ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
+        private ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
         private final Set<String> mPropertyNames = new ArraySet<>();
         private boolean mBuilt = false;
 
@@ -133,8 +133,8 @@
         /** Adds a property to the given type. */
         @NonNull
         public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(propertyConfig);
+            resetIfBuilt();
             String name = propertyConfig.getName();
             if (!mPropertyNames.add(name)) {
                 throw new IllegalSchemaException("Property defined more than once: " + name);
@@ -143,20 +143,22 @@
             return this;
         }
 
-        /**
-         * Constructs a new {@link AppSearchSchema} from the contents of this builder.
-         *
-         * <p>After calling this method, the builder must no longer be used.
-         */
+        /** Constructs a new {@link AppSearchSchema} from the contents of this builder. */
         @NonNull
         public AppSearchSchema build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Bundle bundle = new Bundle();
             bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mSchemaType);
             bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mPropertyBundles);
             mBuilt = true;
             return new AppSearchSchema(bundle);
         }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                mPropertyBundles = new ArrayList<>(mPropertyBundles);
+                mBuilt = false;
+            }
+        }
     }
 
     /**
@@ -251,6 +253,7 @@
         }
 
         @Override
+        @NonNull
         public String toString() {
             return mBundle.toString();
         }
@@ -410,16 +413,14 @@
 
         /** Builder for {@link StringPropertyConfig}. */
         public static final class Builder {
-            private final Bundle mBundle = new Bundle();
-            private boolean mBuilt = false;
+            private final String mPropertyName;
+            private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+            private @IndexingType int mIndexingType = INDEXING_TYPE_NONE;
+            private @TokenizerType int mTokenizerType = TOKENIZER_TYPE_NONE;
 
             /** Creates a new {@link StringPropertyConfig.Builder}. */
             public Builder(@NonNull String propertyName) {
-                mBundle.putString(NAME_FIELD, propertyName);
-                mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_STRING);
-                mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL);
-                mBundle.putInt(INDEXING_TYPE_FIELD, INDEXING_TYPE_NONE);
-                mBundle.putInt(TOKENIZER_TYPE_FIELD, TOKENIZER_TYPE_NONE);
+                mPropertyName = Objects.requireNonNull(propertyName);
             }
 
             /**
@@ -431,10 +432,9 @@
             @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
             @NonNull
             public StringPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
                 Preconditions.checkArgumentInRange(
                         cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
-                mBundle.putInt(CARDINALITY_FIELD, cardinality);
+                mCardinality = cardinality;
                 return this;
             }
 
@@ -446,10 +446,9 @@
              */
             @NonNull
             public StringPropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
                 Preconditions.checkArgumentInRange(
                         indexingType, INDEXING_TYPE_NONE, INDEXING_TYPE_PREFIXES, "indexingType");
-                mBundle.putInt(INDEXING_TYPE_FIELD, indexingType);
+                mIndexingType = indexingType;
                 return this;
             }
 
@@ -466,25 +465,22 @@
              */
             @NonNull
             public StringPropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
                 Preconditions.checkArgumentInRange(
                         tokenizerType, TOKENIZER_TYPE_NONE, TOKENIZER_TYPE_PLAIN, "tokenizerType");
-                mBundle.putInt(TOKENIZER_TYPE_FIELD, tokenizerType);
+                mTokenizerType = tokenizerType;
                 return this;
             }
 
-            /**
-             * Constructs a new {@link StringPropertyConfig} from the contents of this builder.
-             *
-             * <p>After calling this method, the builder must no longer be used.
-             *
-             * @throws IllegalStateException if the builder has already been used
-             */
+            /** Constructs a new {@link StringPropertyConfig} from the contents of this builder. */
             @NonNull
             public StringPropertyConfig build() {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                mBuilt = true;
-                return new StringPropertyConfig(mBundle);
+                Bundle bundle = new Bundle();
+                bundle.putString(NAME_FIELD, mPropertyName);
+                bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_STRING);
+                bundle.putInt(CARDINALITY_FIELD, mCardinality);
+                bundle.putInt(INDEXING_TYPE_FIELD, mIndexingType);
+                bundle.putInt(TOKENIZER_TYPE_FIELD, mTokenizerType);
+                return new StringPropertyConfig(bundle);
             }
         }
     }
@@ -497,14 +493,12 @@
 
         /** Builder for {@link Int64PropertyConfig}. */
         public static final class Builder {
-            private final Bundle mBundle = new Bundle();
-            private boolean mBuilt = false;
+            private final String mPropertyName;
+            private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
 
             /** Creates a new {@link Int64PropertyConfig.Builder}. */
             public Builder(@NonNull String propertyName) {
-                mBundle.putString(NAME_FIELD, propertyName);
-                mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_INT64);
-                mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL);
+                mPropertyName = Objects.requireNonNull(propertyName);
             }
 
             /**
@@ -516,25 +510,20 @@
             @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
             @NonNull
             public Int64PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
                 Preconditions.checkArgumentInRange(
                         cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
-                mBundle.putInt(CARDINALITY_FIELD, cardinality);
+                mCardinality = cardinality;
                 return this;
             }
 
-            /**
-             * Constructs a new {@link Int64PropertyConfig} from the contents of this builder.
-             *
-             * <p>After calling this method, the builder must no longer be used.
-             *
-             * @throws IllegalStateException if the builder has already been used
-             */
+            /** Constructs a new {@link Int64PropertyConfig} from the contents of this builder. */
             @NonNull
             public Int64PropertyConfig build() {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                mBuilt = true;
-                return new Int64PropertyConfig(mBundle);
+                Bundle bundle = new Bundle();
+                bundle.putString(NAME_FIELD, mPropertyName);
+                bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_INT64);
+                bundle.putInt(CARDINALITY_FIELD, mCardinality);
+                return new Int64PropertyConfig(bundle);
             }
         }
     }
@@ -547,14 +536,12 @@
 
         /** Builder for {@link DoublePropertyConfig}. */
         public static final class Builder {
-            private final Bundle mBundle = new Bundle();
-            private boolean mBuilt = false;
+            private final String mPropertyName;
+            private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
 
             /** Creates a new {@link DoublePropertyConfig.Builder}. */
             public Builder(@NonNull String propertyName) {
-                mBundle.putString(NAME_FIELD, propertyName);
-                mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOUBLE);
-                mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL);
+                mPropertyName = Objects.requireNonNull(propertyName);
             }
 
             /**
@@ -566,25 +553,20 @@
             @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
             @NonNull
             public DoublePropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
                 Preconditions.checkArgumentInRange(
                         cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
-                mBundle.putInt(CARDINALITY_FIELD, cardinality);
+                mCardinality = cardinality;
                 return this;
             }
 
-            /**
-             * Constructs a new {@link DoublePropertyConfig} from the contents of this builder.
-             *
-             * <p>After calling this method, the builder must no longer be used.
-             *
-             * @throws IllegalStateException if the builder has already been used
-             */
+            /** Constructs a new {@link DoublePropertyConfig} from the contents of this builder. */
             @NonNull
             public DoublePropertyConfig build() {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                mBuilt = true;
-                return new DoublePropertyConfig(mBundle);
+                Bundle bundle = new Bundle();
+                bundle.putString(NAME_FIELD, mPropertyName);
+                bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOUBLE);
+                bundle.putInt(CARDINALITY_FIELD, mCardinality);
+                return new DoublePropertyConfig(bundle);
             }
         }
     }
@@ -597,14 +579,12 @@
 
         /** Builder for {@link BooleanPropertyConfig}. */
         public static final class Builder {
-            private final Bundle mBundle = new Bundle();
-            private boolean mBuilt = false;
+            private final String mPropertyName;
+            private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
 
             /** Creates a new {@link BooleanPropertyConfig.Builder}. */
             public Builder(@NonNull String propertyName) {
-                mBundle.putString(NAME_FIELD, propertyName);
-                mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BOOLEAN);
-                mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL);
+                mPropertyName = Objects.requireNonNull(propertyName);
             }
 
             /**
@@ -616,25 +596,20 @@
             @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
             @NonNull
             public BooleanPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
                 Preconditions.checkArgumentInRange(
                         cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
-                mBundle.putInt(CARDINALITY_FIELD, cardinality);
+                mCardinality = cardinality;
                 return this;
             }
 
-            /**
-             * Constructs a new {@link BooleanPropertyConfig} from the contents of this builder.
-             *
-             * <p>After calling this method, the builder must no longer be used.
-             *
-             * @throws IllegalStateException if the builder has already been used
-             */
+            /** Constructs a new {@link BooleanPropertyConfig} from the contents of this builder. */
             @NonNull
             public BooleanPropertyConfig build() {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                mBuilt = true;
-                return new BooleanPropertyConfig(mBundle);
+                Bundle bundle = new Bundle();
+                bundle.putString(NAME_FIELD, mPropertyName);
+                bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BOOLEAN);
+                bundle.putInt(CARDINALITY_FIELD, mCardinality);
+                return new BooleanPropertyConfig(bundle);
             }
         }
     }
@@ -647,14 +622,12 @@
 
         /** Builder for {@link BytesPropertyConfig}. */
         public static final class Builder {
-            private final Bundle mBundle = new Bundle();
-            private boolean mBuilt = false;
+            private final String mPropertyName;
+            private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
 
             /** Creates a new {@link BytesPropertyConfig.Builder}. */
             public Builder(@NonNull String propertyName) {
-                mBundle.putString(NAME_FIELD, propertyName);
-                mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BYTES);
-                mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL);
+                mPropertyName = Objects.requireNonNull(propertyName);
             }
 
             /**
@@ -666,25 +639,20 @@
             @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
             @NonNull
             public BytesPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
                 Preconditions.checkArgumentInRange(
                         cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
-                mBundle.putInt(CARDINALITY_FIELD, cardinality);
+                mCardinality = cardinality;
                 return this;
             }
 
-            /**
-             * Constructs a new {@link BytesPropertyConfig} from the contents of this builder.
-             *
-             * <p>After calling this method, the builder must no longer be used.
-             *
-             * @throws IllegalStateException if the builder has already been used
-             */
+            /** Constructs a new {@link BytesPropertyConfig} from the contents of this builder. */
             @NonNull
             public BytesPropertyConfig build() {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                mBuilt = true;
-                return new BytesPropertyConfig(mBundle);
+                Bundle bundle = new Bundle();
+                bundle.putString(NAME_FIELD, mPropertyName);
+                bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_BYTES);
+                bundle.putInt(CARDINALITY_FIELD, mCardinality);
+                return new BytesPropertyConfig(bundle);
             }
         }
     }
@@ -715,20 +683,13 @@
             return mBundle.getBoolean(INDEX_NESTED_PROPERTIES_FIELD);
         }
 
-        /**
-         * Builder for {@link DocumentPropertyConfig}.
-         *
-         * <p>The following properties must be set, or {@link DocumentPropertyConfig} construction
-         * will fail:
-         *
-         * <ul>
-         *   <li>cardinality
-         *   <li>schemaType
-         * </ul>
-         */
+        /** Builder for {@link DocumentPropertyConfig}. */
         public static final class Builder {
-            private final Bundle mBundle = new Bundle();
-            private boolean mBuilt = false;
+            private final String mPropertyName;
+            // TODO(b/181887768): This should be final
+            private String mSchemaType;
+            private @Cardinality int mCardinality = CARDINALITY_OPTIONAL;
+            private boolean mShouldIndexNestedProperties = false;
 
             /**
              * Creates a new {@link DocumentPropertyConfig.Builder}.
@@ -740,11 +701,8 @@
              *     Documents of different types cannot be mixed into a single property.
              */
             public Builder(@NonNull String propertyName, @NonNull String schemaType) {
-                mBundle.putString(NAME_FIELD, propertyName);
-                mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT);
-                mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL);
-                mBundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, false);
-                mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
+                mPropertyName = Objects.requireNonNull(propertyName);
+                mSchemaType = Objects.requireNonNull(schemaType);
             }
 
             /**
@@ -754,10 +712,8 @@
             @Deprecated
             @UnsupportedAppUsage
             public Builder(@NonNull String propertyName) {
-                mBundle.putString(NAME_FIELD, propertyName);
-                mBundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT);
-                mBundle.putInt(CARDINALITY_FIELD, CARDINALITY_OPTIONAL);
-                mBundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, false);
+                mPropertyName = Objects.requireNonNull(propertyName);
+                mSchemaType = null;
             }
 
             /**
@@ -768,7 +724,7 @@
             @UnsupportedAppUsage
             @NonNull
             public Builder setSchemaType(@NonNull String schemaType) {
-                mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
+                mSchemaType = Objects.requireNonNull(schemaType);
                 return this;
             }
 
@@ -781,10 +737,9 @@
             @SuppressWarnings("MissingGetterMatchingBuilder") // getter defined in superclass
             @NonNull
             public DocumentPropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
                 Preconditions.checkArgumentInRange(
                         cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
-                mBundle.putInt(CARDINALITY_FIELD, cardinality);
+                mCardinality = cardinality;
                 return this;
             }
 
@@ -798,8 +753,7 @@
             @NonNull
             public DocumentPropertyConfig.Builder setShouldIndexNestedProperties(
                     boolean indexNestedProperties) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                mBundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, indexNestedProperties);
+                mShouldIndexNestedProperties = indexNestedProperties;
                 return this;
             }
 
@@ -815,19 +769,18 @@
                 return setShouldIndexNestedProperties(indexNestedProperties);
             }
 
-            /**
-             * Constructs a new {@link PropertyConfig} from the contents of this builder.
-             *
-             * <p>After calling this method, the builder must no longer be used.
-             *
-             * @throws IllegalStateException if the builder has already been used (e.g. missing
-             *     {@code dataType}).
-             */
+            /** Constructs a new {@link PropertyConfig} from the contents of this builder. */
             @NonNull
             public DocumentPropertyConfig build() {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                mBuilt = true;
-                return new DocumentPropertyConfig(mBundle);
+                Bundle bundle = new Bundle();
+                bundle.putString(NAME_FIELD, mPropertyName);
+                bundle.putInt(DATA_TYPE_FIELD, DATA_TYPE_DOCUMENT);
+                bundle.putInt(CARDINALITY_FIELD, mCardinality);
+                bundle.putBoolean(INDEX_NESTED_PROPERTIES_FIELD, mShouldIndexNestedProperties);
+                // TODO(b/181887768): Remove checkNotNull after the deprecated constructor (which
+                //  is the only way to get null here) is removed
+                bundle.putString(SCHEMA_TYPE_FIELD, Objects.requireNonNull(mSchemaType));
+                return new DocumentPropertyConfig(bundle);
             }
         }
     }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
index 39a4884..cc48ccb 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -892,64 +892,121 @@
     @Override
     @NonNull
     public String toString() {
-        return bundleToString(mBundle).toString();
+        StringBuilder stringBuilder = new StringBuilder();
+        appendGenericDocumentString(this, /*indentLevel=*/ 0, stringBuilder);
+        return stringBuilder.toString();
     }
 
-    private static StringBuilder bundleToString(Bundle bundle) {
-        StringBuilder stringBuilder = new StringBuilder();
-        try {
-            String[] names = bundle.keySet().toArray(new String[0]);
-            // Sort names to make output deterministic. We need a custom comparator to handle
-            // nulls (arbitrarily putting them first, similar to Comparator.nullsFirst, which is
-            // only available since N).
-            Arrays.sort(
-                    names,
-                    (@Nullable String s1, @Nullable String s2) -> {
-                        if (s1 == null) {
-                            return s2 == null ? 0 : -1;
-                        } else if (s2 == null) {
-                            return 1;
-                        } else {
-                            return s1.compareTo(s2);
-                        }
-                    });
-            for (String name : names) {
-                stringBuilder.append("{ name: '").append(name).append("' value: ");
-                Object valueObject = bundle.get(name);
-                if (valueObject == null) {
-                    stringBuilder.append("<null>");
-                } else if (valueObject instanceof Bundle) {
-                    stringBuilder.append(bundleToString((Bundle) valueObject));
-                } else if (valueObject.getClass().isArray()) {
-                    stringBuilder.append("[ ");
-                    for (int i = 0; i < Array.getLength(valueObject); i++) {
-                        Object element = Array.get(valueObject, i);
-                        stringBuilder.append("'");
-                        if (element instanceof Bundle) {
-                            stringBuilder.append(bundleToString((Bundle) element));
-                        } else {
-                            stringBuilder.append(Array.get(valueObject, i));
-                        }
-                        stringBuilder.append("' ");
-                    }
-                    stringBuilder.append("]");
-                } else if (valueObject instanceof List) {
-                    @SuppressWarnings("unchecked")
-                    List<Bundle> bundles = (List<Bundle>) valueObject;
-                    for (int i = 0; i < bundles.size(); i++) {
-                        stringBuilder.append(bundleToString(bundles.get(i)));
-                    }
-                } else {
-                    stringBuilder.append(valueObject.toString());
-                }
-                stringBuilder.append(" } ");
+    private static void appendGenericDocumentString(
+            @NonNull GenericDocument document, int indentLevel, @NonNull StringBuilder builder) {
+        Objects.requireNonNull(document);
+        Objects.requireNonNull(builder);
+
+        builder.append(getIndent(indentLevel)).append("{\n");
+
+        String indent1 = getIndent(indentLevel + 1);
+
+        builder.append(indent1)
+                .append("namespace: \"")
+                .append(document.getNamespace())
+                .append("\",\n");
+
+        builder.append(indent1).append("id: \"").append(document.getId()).append("\",\n");
+
+        builder.append(indent1).append("score: ").append(document.getScore()).append(",\n");
+
+        builder.append(indent1)
+                .append("schemaType: \"")
+                .append(document.getSchemaType())
+                .append("\",\n");
+
+        builder.append(indent1)
+                .append("creationTimestampMillis: ")
+                .append(document.getCreationTimestampMillis())
+                .append(",\n");
+
+        builder.append(indent1)
+                .append("timeToLiveMillis: ")
+                .append(document.getTtlMillis())
+                .append(",\n");
+
+        builder.append(indent1).append("properties: {\n");
+
+        String[] sortedProperties = document.getPropertyNames().toArray(new String[0]);
+        Arrays.sort(sortedProperties);
+
+        for (int i = 0; i < sortedProperties.length; i++) {
+            Object property = document.getProperty(sortedProperties[i]);
+            builder.append(getIndent(indentLevel + 2))
+                    .append("\"")
+                    .append(sortedProperties[i])
+                    .append("\"")
+                    .append(": ");
+            appendPropertyString(property, indentLevel + 2, builder);
+            if (i != sortedProperties.length - 1) {
+                builder.append(",\n");
             }
-        } catch (RuntimeException e) {
-            // Catch any exceptions here since corrupt Bundles can throw different types of
-            // exceptions (e.g. b/38445840 & b/68937025).
-            stringBuilder.append("<error>");
         }
-        return stringBuilder;
+
+        builder.append("\n");
+        builder.append(indent1).append("}");
+
+        builder.append("\n");
+        builder.append(getIndent(indentLevel)).append("}");
+    }
+
+    /**
+     * Appends a string for the given property to the given builder.
+     *
+     * @param property property object to create string for.
+     * @param indentLevel base indent level for property.
+     * @param builder the builder to append to.
+     */
+    private static void appendPropertyString(
+            @NonNull Object property, int indentLevel, @NonNull StringBuilder builder) {
+        Objects.requireNonNull(property);
+        Objects.requireNonNull(builder);
+
+        builder.append("[");
+        if (property instanceof GenericDocument[]) {
+            GenericDocument[] documentValues = (GenericDocument[]) property;
+            for (int i = 0; i < documentValues.length; ++i) {
+                builder.append("\n");
+                appendGenericDocumentString(documentValues[i], indentLevel + 1, builder);
+                if (i != documentValues.length - 1) {
+                    builder.append(", ");
+                }
+                builder.append("\n");
+            }
+            builder.append(getIndent(indentLevel));
+        } else {
+            int propertyArrLength = Array.getLength(property);
+            for (int i = 0; i < propertyArrLength; i++) {
+                Object propertyElement = Array.get(property, i);
+                if (propertyElement instanceof String) {
+                    builder.append("\"").append(propertyElement).append("\"");
+                } else if (propertyElement instanceof byte[]) {
+                    builder.append(Arrays.toString((byte[]) propertyElement));
+                } else {
+                    builder.append(propertyElement);
+                }
+                if (i != propertyArrLength - 1) {
+                    builder.append(", ");
+                }
+            }
+        }
+
+        builder.append("]");
+    }
+
+    /** Appends a string for given indent level to the given builder. */
+    @NonNull
+    private static String getIndent(int indentLevel) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < indentLevel; ++i) {
+            builder.append("  ");
+        }
+        return builder.toString();
     }
 
     /**
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetByDocumentIdRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetByDocumentIdRequest.java
index 58fd8be..e324b9f 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GetByDocumentIdRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetByDocumentIdRequest.java
@@ -20,8 +20,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -102,15 +100,11 @@
         return mTypePropertyPathsMap;
     }
 
-    /**
-     * Builder for {@link GetByDocumentIdRequest} objects.
-     *
-     * <p>Once {@link #build} is called, the instance can no longer be used.
-     */
+    /** Builder for {@link GetByDocumentIdRequest} objects. */
     public static final class Builder {
         private final String mNamespace;
-        private final Set<String> mIds = new ArraySet<>();
-        private final Map<String, List<String>> mProjectionTypePropertyPaths = new ArrayMap<>();
+        private ArraySet<String> mIds = new ArraySet<>();
+        private ArrayMap<String, List<String>> mProjectionTypePropertyPaths = new ArrayMap<>();
         private boolean mBuilt = false;
 
         /** Creates a {@link GetByDocumentIdRequest.Builder} instance. */
@@ -118,26 +112,19 @@
             mNamespace = Objects.requireNonNull(namespace);
         }
 
-        /**
-         * Adds one or more document IDs to the request.
-         *
-         * @throws IllegalStateException if the builder has already been used.
-         */
+        /** Adds one or more document IDs to the request. */
         @NonNull
         public Builder addIds(@NonNull String... ids) {
             Objects.requireNonNull(ids);
+            resetIfBuilt();
             return addIds(Arrays.asList(ids));
         }
 
-        /**
-         * Adds a collection of IDs to the request.
-         *
-         * @throws IllegalStateException if the builder has already been used.
-         */
+        /** Adds a collection of IDs to the request. */
         @NonNull
         public Builder addIds(@NonNull Collection<String> ids) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(ids);
+            resetIfBuilt();
             mIds.addAll(ids);
             return this;
         }
@@ -156,15 +143,14 @@
          * apply to all results, excepting any types that have their own, specific property paths
          * set.
          *
-         * @throws IllegalStateException if the builder has already been used.
          * @see SearchSpec.Builder#addProjection
          */
         @NonNull
         public Builder addProjection(
                 @NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(schemaType);
             Objects.requireNonNull(propertyPaths);
+            resetIfBuilt();
             List<String> propertyPathsList = new ArrayList<>(propertyPaths.size());
             for (String propertyPath : propertyPaths) {
                 Objects.requireNonNull(propertyPath);
@@ -174,16 +160,23 @@
             return this;
         }
 
-        /**
-         * Builds a new {@link GetByDocumentIdRequest}.
-         *
-         * @throws IllegalStateException if the builder has already been used.
-         */
+        /** Builds a new {@link GetByDocumentIdRequest}. */
         @NonNull
         public GetByDocumentIdRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             mBuilt = true;
-            return new GetByDocumentIdRequest(mNamespace, mIds, mProjectionTypePropertyPaths);
+            return new GetByDocumentIdRequest(
+                    mNamespace, new ArraySet<>(mIds), new ArrayMap<>(mProjectionTypePropertyPaths));
+        }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                mIds = new ArraySet<>(mIds);
+                // No need to clone each propertyPathsList inside mProjectionTypePropertyPaths since
+                // the builder only replaces it, never adds to it. So even if the builder is used
+                // again, the previous one will remain with the object.
+                mProjectionTypePropertyPaths = new ArrayMap<>(mProjectionTypePropertyPaths);
+                mBuilt = false;
+            }
         }
     }
 }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java
index 6f8cbe8..8816c78 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetSchemaResponse.java
@@ -21,8 +21,6 @@
 import android.os.Bundle;
 import android.util.ArraySet;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.ArrayList;
 import java.util.Objects;
 import java.util.Set;
@@ -76,8 +74,8 @@
     /** Builder for {@link GetSchemaResponse} objects. */
     public static final class Builder {
         private int mVersion = 0;
+        private ArrayList<Bundle> mSchemaBundles = new ArrayList<>();
         private boolean mBuilt = false;
-        private final ArrayList<Bundle> mSchemaBundles = new ArrayList<>();
 
         /**
          * Sets the database overall schema version.
@@ -86,6 +84,7 @@
          */
         @NonNull
         public Builder setVersion(@IntRange(from = 0) int version) {
+            resetIfBuilt();
             mVersion = version;
             return this;
         }
@@ -93,6 +92,8 @@
         /** Adds one {@link AppSearchSchema} to the schema list. */
         @NonNull
         public Builder addSchema(@NonNull AppSearchSchema schema) {
+            Objects.requireNonNull(schema);
+            resetIfBuilt();
             mSchemaBundles.add(schema.getBundle());
             return this;
         }
@@ -100,12 +101,18 @@
         /** Builds a {@link GetSchemaResponse} object. */
         @NonNull
         public GetSchemaResponse build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Bundle bundle = new Bundle();
             bundle.putInt(VERSION_FIELD, mVersion);
             bundle.putParcelableArrayList(SCHEMAS_FIELD, mSchemaBundles);
             mBuilt = true;
             return new GetSchemaResponse(bundle);
         }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                mSchemaBundles = new ArrayList<>(mSchemaBundles);
+                mBuilt = false;
+            }
+        }
     }
 }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
index b49e0e8..3424128 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
@@ -19,8 +19,6 @@
 
 import android.annotation.NonNull;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -46,50 +44,41 @@
         return Collections.unmodifiableList(mDocuments);
     }
 
-    /**
-     * Builder for {@link PutDocumentsRequest} objects.
-     *
-     * <p>Once {@link #build} is called, the instance can no longer be used.
-     */
+    /** Builder for {@link PutDocumentsRequest} objects. */
     public static final class Builder {
-        private final List<GenericDocument> mDocuments = new ArrayList<>();
+        private ArrayList<GenericDocument> mDocuments = new ArrayList<>();
         private boolean mBuilt = false;
 
-        /**
-         * Adds one or more {@link GenericDocument} objects to the request.
-         *
-         * @throws IllegalStateException if the builder has already been used.
-         */
+        /** Adds one or more {@link GenericDocument} objects to the request. */
         @NonNull
         public Builder addGenericDocuments(@NonNull GenericDocument... documents) {
             Objects.requireNonNull(documents);
+            resetIfBuilt();
             return addGenericDocuments(Arrays.asList(documents));
         }
 
-        /**
-         * Adds a collection of {@link GenericDocument} objects to the request.
-         *
-         * @throws IllegalStateException if the builder has already been used.
-         */
+        /** Adds a collection of {@link GenericDocument} objects to the request. */
         @NonNull
         public Builder addGenericDocuments(
                 @NonNull Collection<? extends GenericDocument> documents) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(documents);
+            resetIfBuilt();
             mDocuments.addAll(documents);
             return this;
         }
 
-        /**
-         * Creates a new {@link PutDocumentsRequest} object.
-         *
-         * @throws IllegalStateException if the builder has already been used.
-         */
+        /** Creates a new {@link PutDocumentsRequest} object. */
         @NonNull
         public PutDocumentsRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             mBuilt = true;
             return new PutDocumentsRequest(mDocuments);
         }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                mDocuments = new ArrayList<>(mDocuments);
+                mBuilt = false;
+            }
+        }
     }
 }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByDocumentIdRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByDocumentIdRequest.java
index 1afbe27..b86fd27 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByDocumentIdRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByDocumentIdRequest.java
@@ -19,8 +19,6 @@
 import android.annotation.NonNull;
 import android.util.ArraySet;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -54,14 +52,10 @@
         return Collections.unmodifiableSet(mIds);
     }
 
-    /**
-     * Builder for {@link RemoveByDocumentIdRequest} objects.
-     *
-     * <p>Once {@link #build} is called, the instance can no longer be used.
-     */
+    /** Builder for {@link RemoveByDocumentIdRequest} objects. */
     public static final class Builder {
         private final String mNamespace;
-        private final Set<String> mIds = new ArraySet<>();
+        private ArraySet<String> mIds = new ArraySet<>();
         private boolean mBuilt = false;
 
         /** Creates a {@link RemoveByDocumentIdRequest.Builder} instance. */
@@ -69,40 +63,35 @@
             mNamespace = Objects.requireNonNull(namespace);
         }
 
-        /**
-         * Adds one or more document IDs to the request.
-         *
-         * @throws IllegalStateException if the builder has already been used.
-         */
+        /** Adds one or more document IDs to the request. */
         @NonNull
         public Builder addIds(@NonNull String... ids) {
             Objects.requireNonNull(ids);
+            resetIfBuilt();
             return addIds(Arrays.asList(ids));
         }
 
-        /**
-         * Adds a collection of IDs to the request.
-         *
-         * @throws IllegalStateException if the builder has already been used.
-         */
+        /** Adds a collection of IDs to the request. */
         @NonNull
         public Builder addIds(@NonNull Collection<String> ids) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(ids);
+            resetIfBuilt();
             mIds.addAll(ids);
             return this;
         }
 
-        /**
-         * Builds a new {@link RemoveByDocumentIdRequest}.
-         *
-         * @throws IllegalStateException if the builder has already been used.
-         */
+        /** Builds a new {@link RemoveByDocumentIdRequest}. */
         @NonNull
         public RemoveByDocumentIdRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             mBuilt = true;
             return new RemoveByDocumentIdRequest(mNamespace, mIds);
         }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                mIds = new ArraySet<>(mIds);
+                mBuilt = false;
+            }
+        }
     }
 }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java
index 3947ba7..b6575c2 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportSystemUsageRequest.java
@@ -19,8 +19,6 @@
 import android.annotation.CurrentTimeMillisLong;
 import android.annotation.NonNull;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Objects;
 
 /**
@@ -94,7 +92,6 @@
         private final String mNamespace;
         private final String mDocumentId;
         private Long mUsageTimestampMillis;
-        private boolean mBuilt = false;
 
         /** Creates a {@link ReportSystemUsageRequest.Builder} instance. */
         public Builder(
@@ -116,29 +113,20 @@
          *
          * <p>If unset, this defaults to the current timestamp at the time that the {@link
          * ReportSystemUsageRequest} is constructed.
-         *
-         * @throws IllegalStateException if the builder has already been used
          */
         @NonNull
         public ReportSystemUsageRequest.Builder setUsageTimestampMillis(
                 @CurrentTimeMillisLong long usageTimestampMillis) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             mUsageTimestampMillis = usageTimestampMillis;
             return this;
         }
 
-        /**
-         * Builds a new {@link ReportSystemUsageRequest}.
-         *
-         * @throws IllegalStateException if the builder has already been used
-         */
+        /** Builds a new {@link ReportSystemUsageRequest}. */
         @NonNull
         public ReportSystemUsageRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             if (mUsageTimestampMillis == null) {
                 mUsageTimestampMillis = System.currentTimeMillis();
             }
-            mBuilt = true;
             return new ReportSystemUsageRequest(
                     mPackageName, mDatabase, mNamespace, mDocumentId, mUsageTimestampMillis);
         }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
index 5cb59b3..59fa6e0 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/ReportUsageRequest.java
@@ -20,8 +20,6 @@
 import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Objects;
 
 /**
@@ -72,7 +70,6 @@
         // TODO(b/181887768): Make this final
         private String mDocumentId;
         private Long mUsageTimestampMillis;
-        private boolean mBuilt = false;
 
         /** Creates a {@link ReportUsageRequest.Builder} instance. */
         public Builder(@NonNull String namespace, @NonNull String documentId) {
@@ -122,29 +119,20 @@
          *
          * <p>If unset, this defaults to the current timestamp at the time that the {@link
          * ReportUsageRequest} is constructed.
-         *
-         * @throws IllegalStateException if the builder has already been used
          */
         @NonNull
         public ReportUsageRequest.Builder setUsageTimestampMillis(
                 @CurrentTimeMillisLong long usageTimestampMillis) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             mUsageTimestampMillis = usageTimestampMillis;
             return this;
         }
 
-        /**
-         * Builds a new {@link ReportUsageRequest}.
-         *
-         * @throws IllegalStateException if the builder has already been used
-         */
+        /** Builds a new {@link ReportUsageRequest}. */
         @NonNull
         public ReportUsageRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             if (mUsageTimestampMillis == null) {
                 mUsageTimestampMillis = System.currentTimeMillis();
             }
-            mBuilt = true;
             return new ReportUsageRequest(mNamespace, mDocumentId, mUsageTimestampMillis);
         }
     }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
index 9a1796c..4beb667 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Bundle;
 
 import com.android.internal.util.Preconditions;
@@ -82,8 +83,12 @@
         return mDocument;
     }
 
-    /** @deprecated This method exists only for dogfooder transition and must be removed. */
+    /**
+     * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed.
+     * @hide
+     */
     @Deprecated
+    @UnsupportedAppUsage
     @NonNull
     public List<MatchInfo> getMatches() {
         return getMatchInfos();
@@ -164,10 +169,12 @@
 
     /** Builder for {@link SearchResult} objects. */
     public static final class Builder {
-        private final Bundle mBundle = new Bundle();
-        private final ArrayList<Bundle> mMatchInfos = new ArrayList<>();
-
-        private boolean mBuilt;
+        private final String mPackageName;
+        private final String mDatabaseName;
+        private ArrayList<Bundle> mMatchInfoBundles = new ArrayList<>();
+        private GenericDocument mGenericDocument;
+        private double mRankingSignal;
+        private boolean mBuilt = false;
 
         /**
          * Constructs a new builder for {@link SearchResult} objects.
@@ -176,24 +183,25 @@
          * @param databaseName the database name the matched document belongs to.
          */
         public Builder(@NonNull String packageName, @NonNull String databaseName) {
-            mBundle.putString(PACKAGE_NAME_FIELD, Objects.requireNonNull(packageName));
-            mBundle.putString(DATABASE_NAME_FIELD, Objects.requireNonNull(databaseName));
+            mPackageName = Objects.requireNonNull(packageName);
+            mDatabaseName = Objects.requireNonNull(databaseName);
         }
 
-        /**
-         * Sets the document which matched.
-         *
-         * @throws IllegalStateException if the builder has already been used
-         */
+        /** Sets the document which matched. */
         @NonNull
         public Builder setGenericDocument(@NonNull GenericDocument document) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putBundle(DOCUMENT_FIELD, document.getBundle());
+            Objects.requireNonNull(document);
+            resetIfBuilt();
+            mGenericDocument = document;
             return this;
         }
 
-        /** @deprecated This method exists only for dogfooder transition and must be removed. */
+        /**
+         * @deprecated TODO(b/181887768): Exists for dogfood transition; must be removed.
+         * @hide
+         */
         @Deprecated
+        @UnsupportedAppUsage
         @NonNull
         public Builder addMatch(@NonNull MatchInfo matchInfo) {
             return addMatchInfo(matchInfo);
@@ -202,34 +210,41 @@
         /** Adds another match to this SearchResult. */
         @NonNull
         public Builder addMatchInfo(@NonNull MatchInfo matchInfo) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkState(
                     matchInfo.mDocument == null,
                     "This MatchInfo is already associated with a SearchResult and can't be "
                             + "reassigned");
-            mMatchInfos.add(matchInfo.mBundle);
+            resetIfBuilt();
+            mMatchInfoBundles.add(matchInfo.mBundle);
             return this;
         }
 
         /** Sets the ranking signal of the matched document in this SearchResult. */
         @NonNull
         public Builder setRankingSignal(double rankingSignal) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putDouble(RANKING_SIGNAL_FIELD, rankingSignal);
+            resetIfBuilt();
+            mRankingSignal = rankingSignal;
             return this;
         }
 
-        /**
-         * Constructs a new {@link SearchResult}.
-         *
-         * @throws IllegalStateException if the builder has already been used
-         */
+        /** Constructs a new {@link SearchResult}. */
         @NonNull
         public SearchResult build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putParcelableArrayList(MATCH_INFOS_FIELD, mMatchInfos);
+            Bundle bundle = new Bundle();
+            bundle.putString(PACKAGE_NAME_FIELD, mPackageName);
+            bundle.putString(DATABASE_NAME_FIELD, mDatabaseName);
+            bundle.putBundle(DOCUMENT_FIELD, mGenericDocument.getBundle());
+            bundle.putDouble(RANKING_SIGNAL_FIELD, mRankingSignal);
+            bundle.putParcelableArrayList(MATCH_INFOS_FIELD, mMatchInfoBundles);
             mBuilt = true;
-            return new SearchResult(mBundle);
+            return new SearchResult(bundle);
+        }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                mMatchInfoBundles = new ArrayList<>(mMatchInfoBundles);
+                mBuilt = false;
+            }
         }
     }
 
@@ -441,8 +456,9 @@
 
         /** Builder for {@link MatchInfo} objects. */
         public static final class Builder {
-            private final Bundle mBundle = new Bundle();
-            private boolean mBuilt = false;
+            private final String mPropertyPath;
+            private MatchRange mExactMatchRange = new MatchRange(0, 0);
+            private MatchRange mSnippetRange = new MatchRange(0, 0);
 
             /**
              * Creates a new {@link MatchInfo.Builder} reporting a match with the given property
@@ -458,49 +474,33 @@
              *                     which property in the document these snippets correspond to.
              */
             public Builder(@NonNull String propertyPath) {
-                mBundle.putString(
-                        SearchResult.MatchInfo.PROPERTY_PATH_FIELD,
-                        Objects.requireNonNull(propertyPath));
+                mPropertyPath = Objects.requireNonNull(propertyPath);
             }
 
-            /**
-             * Sets the exact {@link MatchRange} corresponding to the given entry.
-             *
-             * @throws IllegalStateException if the builder has already been used
-             */
+            /** Sets the exact {@link MatchRange} corresponding to the given entry. */
             @NonNull
             public Builder setExactMatchRange(@NonNull MatchRange matchRange) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                Objects.requireNonNull(matchRange);
-                mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_LOWER_FIELD, matchRange.getStart());
-                mBundle.putInt(MatchInfo.EXACT_MATCH_RANGE_UPPER_FIELD, matchRange.getEnd());
+                mExactMatchRange = Objects.requireNonNull(matchRange);
                 return this;
             }
 
-            /**
-             * Sets the snippet {@link MatchRange} corresponding to the given entry.
-             *
-             * @throws IllegalStateException if the builder has already been used
-             */
+            /** Sets the snippet {@link MatchRange} corresponding to the given entry. */
             @NonNull
             public Builder setSnippetRange(@NonNull MatchRange matchRange) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                Objects.requireNonNull(matchRange);
-                mBundle.putInt(MatchInfo.SNIPPET_RANGE_LOWER_FIELD, matchRange.getStart());
-                mBundle.putInt(MatchInfo.SNIPPET_RANGE_UPPER_FIELD, matchRange.getEnd());
+                mSnippetRange = Objects.requireNonNull(matchRange);
                 return this;
             }
 
-            /**
-             * Constructs a new {@link MatchInfo}.
-             *
-             * @throws IllegalStateException if the builder has already been used
-             */
+            /** Constructs a new {@link MatchInfo}. */
             @NonNull
             public MatchInfo build() {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                mBuilt = true;
-                return new MatchInfo(mBundle, /*document=*/ null);
+                Bundle bundle = new Bundle();
+                bundle.putString(SearchResult.MatchInfo.PROPERTY_PATH_FIELD, mPropertyPath);
+                bundle.putInt(MatchInfo.EXACT_MATCH_RANGE_LOWER_FIELD, mExactMatchRange.getStart());
+                bundle.putInt(MatchInfo.EXACT_MATCH_RANGE_UPPER_FIELD, mExactMatchRange.getEnd());
+                bundle.putInt(MatchInfo.SNIPPET_RANGE_LOWER_FIELD, mSnippetRange.getStart());
+                bundle.putInt(MatchInfo.SNIPPET_RANGE_UPPER_FIELD, mSnippetRange.getEnd());
+                return new MatchInfo(bundle, /*document=*/ null);
             }
         }
     }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
index 1c57c75..5abd4f6 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
@@ -20,6 +20,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
+import android.app.appsearch.util.BundleUtil;
 import android.os.Bundle;
 import android.util.ArrayMap;
 
@@ -310,22 +311,22 @@
 
     /** Builder for {@link SearchSpec objects}. */
     public static final class Builder {
+        private ArrayList<String> mSchemas = new ArrayList<>();
+        private ArrayList<String> mNamespaces = new ArrayList<>();
+        private ArrayList<String> mPackageNames = new ArrayList<>();
+        private Bundle mProjectionTypePropertyMasks = new Bundle();
 
-        private final Bundle mBundle;
-        private final ArrayList<String> mSchemas = new ArrayList<>();
-        private final ArrayList<String> mNamespaces = new ArrayList<>();
-        private final ArrayList<String> mPackageNames = new ArrayList<>();
-        private final Bundle mProjectionTypePropertyMasks = new Bundle();
+        private int mResultCountPerPage = DEFAULT_NUM_PER_PAGE;
+        private @TermMatch int mTermMatchType = TERM_MATCH_PREFIX;
+        private int mSnippetCount = 0;
+        private int mSnippetCountPerProperty = MAX_SNIPPET_PER_PROPERTY_COUNT;
+        private int mMaxSnippetSize = 0;
+        private @RankingStrategy int mRankingStrategy = RANKING_STRATEGY_NONE;
+        private @Order int mOrder = ORDER_DESCENDING;
+        private @GroupingType int mGroupingTypeFlags = 0;
+        private int mGroupingLimit = 0;
         private boolean mBuilt = false;
 
-        /** Creates a new {@link SearchSpec.Builder}. */
-        public Builder() {
-            mBundle = new Bundle();
-            mBundle.putInt(NUM_PER_PAGE_FIELD, DEFAULT_NUM_PER_PAGE);
-            mBundle.putInt(TERM_MATCH_TYPE_FIELD, TERM_MATCH_PREFIX);
-            mBundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, MAX_SNIPPET_PER_PROPERTY_COUNT);
-        }
-
         /**
          * Indicates how the query terms should match {@code TermMatchCode} in the index.
          *
@@ -333,11 +334,11 @@
          * SearchSpec#TERM_MATCH_PREFIX}.
          */
         @NonNull
-        public Builder setTermMatch(@TermMatch int termMatchTypeCode) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
+        public Builder setTermMatch(@TermMatch int termMatchType) {
             Preconditions.checkArgumentInRange(
-                    termMatchTypeCode, TERM_MATCH_EXACT_ONLY, TERM_MATCH_PREFIX, "Term match type");
-            mBundle.putInt(TERM_MATCH_TYPE_FIELD, termMatchTypeCode);
+                    termMatchType, TERM_MATCH_EXACT_ONLY, TERM_MATCH_PREFIX, "Term match type");
+            resetIfBuilt();
+            mTermMatchType = termMatchType;
             return this;
         }
 
@@ -350,7 +351,7 @@
         @NonNull
         public Builder addFilterSchemas(@NonNull String... schemas) {
             Objects.requireNonNull(schemas);
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            resetIfBuilt();
             return addFilterSchemas(Arrays.asList(schemas));
         }
 
@@ -363,7 +364,7 @@
         @NonNull
         public Builder addFilterSchemas(@NonNull Collection<String> schemas) {
             Objects.requireNonNull(schemas);
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            resetIfBuilt();
             mSchemas.addAll(schemas);
             return this;
         }
@@ -377,7 +378,7 @@
         @NonNull
         public Builder addFilterNamespaces(@NonNull String... namespaces) {
             Objects.requireNonNull(namespaces);
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            resetIfBuilt();
             return addFilterNamespaces(Arrays.asList(namespaces));
         }
 
@@ -390,7 +391,7 @@
         @NonNull
         public Builder addFilterNamespaces(@NonNull Collection<String> namespaces) {
             Objects.requireNonNull(namespaces);
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            resetIfBuilt();
             mNamespaces.addAll(namespaces);
             return this;
         }
@@ -406,7 +407,7 @@
         @NonNull
         public Builder addFilterPackageNames(@NonNull String... packageNames) {
             Objects.requireNonNull(packageNames);
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            resetIfBuilt();
             return addFilterPackageNames(Arrays.asList(packageNames));
         }
 
@@ -421,7 +422,7 @@
         @NonNull
         public Builder addFilterPackageNames(@NonNull Collection<String> packageNames) {
             Objects.requireNonNull(packageNames);
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            resetIfBuilt();
             mPackageNames.addAll(packageNames);
             return this;
         }
@@ -433,23 +434,24 @@
          */
         @NonNull
         public SearchSpec.Builder setResultCountPerPage(
-                @IntRange(from = 0, to = MAX_NUM_PER_PAGE) int numPerPage) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkArgumentInRange(numPerPage, 0, MAX_NUM_PER_PAGE, "NumPerPage");
-            mBundle.putInt(NUM_PER_PAGE_FIELD, numPerPage);
+                @IntRange(from = 0, to = MAX_NUM_PER_PAGE) int resultCountPerPage) {
+            Preconditions.checkArgumentInRange(
+                    resultCountPerPage, 0, MAX_NUM_PER_PAGE, "resultCountPerPage");
+            resetIfBuilt();
+            mResultCountPerPage = resultCountPerPage;
             return this;
         }
 
         /** Sets ranking strategy for AppSearch results. */
         @NonNull
         public Builder setRankingStrategy(@RankingStrategy int rankingStrategy) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkArgumentInRange(
                     rankingStrategy,
                     RANKING_STRATEGY_NONE,
                     RANKING_STRATEGY_SYSTEM_USAGE_LAST_USED_TIMESTAMP,
                     "Result ranking strategy");
-            mBundle.putInt(RANKING_STRATEGY_FIELD, rankingStrategy);
+            resetIfBuilt();
+            mRankingStrategy = rankingStrategy;
             return this;
         }
 
@@ -461,10 +463,10 @@
          */
         @NonNull
         public Builder setOrder(@Order int order) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkArgumentInRange(
                     order, ORDER_DESCENDING, ORDER_ASCENDING, "Result ranking order");
-            mBundle.putInt(ORDER_FIELD, order);
+            resetIfBuilt();
+            mOrder = order;
             return this;
         }
 
@@ -481,9 +483,9 @@
         @NonNull
         public SearchSpec.Builder setSnippetCount(
                 @IntRange(from = 0, to = MAX_SNIPPET_COUNT) int snippetCount) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkArgumentInRange(snippetCount, 0, MAX_SNIPPET_COUNT, "snippetCount");
-            mBundle.putInt(SNIPPET_COUNT_FIELD, snippetCount);
+            resetIfBuilt();
+            mSnippetCount = snippetCount;
             return this;
         }
 
@@ -502,13 +504,13 @@
         public SearchSpec.Builder setSnippetCountPerProperty(
                 @IntRange(from = 0, to = MAX_SNIPPET_PER_PROPERTY_COUNT)
                         int snippetCountPerProperty) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkArgumentInRange(
                     snippetCountPerProperty,
                     0,
                     MAX_SNIPPET_PER_PROPERTY_COUNT,
                     "snippetCountPerProperty");
-            mBundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, snippetCountPerProperty);
+            resetIfBuilt();
+            mSnippetCountPerProperty = snippetCountPerProperty;
             return this;
         }
 
@@ -527,10 +529,10 @@
         @NonNull
         public SearchSpec.Builder setMaxSnippetSize(
                 @IntRange(from = 0, to = MAX_SNIPPET_SIZE_LIMIT) int maxSnippetSize) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkArgumentInRange(
                     maxSnippetSize, 0, MAX_SNIPPET_SIZE_LIMIT, "maxSnippetSize");
-            mBundle.putInt(MAX_SNIPPET_FIELD, maxSnippetSize);
+            resetIfBuilt();
+            mMaxSnippetSize = maxSnippetSize;
             return this;
         }
 
@@ -599,9 +601,9 @@
         @NonNull
         public SearchSpec.Builder addProjection(
                 @NonNull String schema, @NonNull Collection<String> propertyPaths) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(schema);
             Objects.requireNonNull(propertyPaths);
+            resetIfBuilt();
             ArrayList<String> propertyPathsArrayList = new ArrayList<>(propertyPaths.size());
             for (String propertyPath : propertyPaths) {
                 Objects.requireNonNull(propertyPath);
@@ -634,25 +636,41 @@
         public Builder setResultGrouping(@GroupingType int groupingTypeFlags, int limit) {
             Preconditions.checkState(
                     groupingTypeFlags != 0, "Result grouping type cannot be zero.");
-            mBundle.putInt(RESULT_GROUPING_TYPE_FLAGS, groupingTypeFlags);
-            mBundle.putInt(RESULT_GROUPING_LIMIT, limit);
+            resetIfBuilt();
+            mGroupingTypeFlags = groupingTypeFlags;
+            mGroupingLimit = limit;
             return this;
         }
 
-        /**
-         * Constructs a new {@link SearchSpec} from the contents of this builder.
-         *
-         * <p>After calling this method, the builder must no longer be used.
-         */
+        /** Constructs a new {@link SearchSpec} from the contents of this builder. */
         @NonNull
         public SearchSpec build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces);
-            mBundle.putStringArrayList(SCHEMA_FIELD, mSchemas);
-            mBundle.putStringArrayList(PACKAGE_NAME_FIELD, mPackageNames);
-            mBundle.putBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD, mProjectionTypePropertyMasks);
+            Bundle bundle = new Bundle();
+            bundle.putStringArrayList(SCHEMA_FIELD, mSchemas);
+            bundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces);
+            bundle.putStringArrayList(PACKAGE_NAME_FIELD, mPackageNames);
+            bundle.putBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD, mProjectionTypePropertyMasks);
+            bundle.putInt(NUM_PER_PAGE_FIELD, mResultCountPerPage);
+            bundle.putInt(TERM_MATCH_TYPE_FIELD, mTermMatchType);
+            bundle.putInt(SNIPPET_COUNT_FIELD, mSnippetCount);
+            bundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, mSnippetCountPerProperty);
+            bundle.putInt(MAX_SNIPPET_FIELD, mMaxSnippetSize);
+            bundle.putInt(RANKING_STRATEGY_FIELD, mRankingStrategy);
+            bundle.putInt(ORDER_FIELD, mOrder);
+            bundle.putInt(RESULT_GROUPING_TYPE_FLAGS, mGroupingTypeFlags);
+            bundle.putInt(RESULT_GROUPING_LIMIT, mGroupingLimit);
             mBuilt = true;
-            return new SearchSpec(mBundle);
+            return new SearchSpec(bundle);
+        }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                mSchemas = new ArrayList<>(mSchemas);
+                mNamespaces = new ArrayList<>(mNamespaces);
+                mPackageNames = new ArrayList<>(mPackageNames);
+                mProjectionTypePropertyMasks = BundleUtil.deepCopy(mProjectionTypePropertyMasks);
+                mBuilt = false;
+            }
         }
     }
 }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index 275b2c3..96002c5 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -167,17 +167,13 @@
         return mVersion;
     }
 
-    /**
-     * Builder for {@link SetSchemaRequest} objects.
-     *
-     * <p>Once {@link #build} is called, the instance can no longer be used.
-     */
+    /** Builder for {@link SetSchemaRequest} objects. */
     public static final class Builder {
-        private final Set<AppSearchSchema> mSchemas = new ArraySet<>();
-        private final Set<String> mSchemasNotDisplayedBySystem = new ArraySet<>();
-        private final Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
+        private ArraySet<AppSearchSchema> mSchemas = new ArraySet<>();
+        private ArraySet<String> mSchemasNotDisplayedBySystem = new ArraySet<>();
+        private ArrayMap<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
                 new ArrayMap<>();
-        private final Map<String, Migrator> mMigrators = new ArrayMap<>();
+        private ArrayMap<String, Migrator> mMigrators = new ArrayMap<>();
         private boolean mForceOverride = false;
         private int mVersion = 1;
         private boolean mBuilt = false;
@@ -188,12 +184,11 @@
          * <p>An {@link AppSearchSchema} object represents one type of structured data.
          *
          * <p>Any documents of these types will be displayed on system UI surfaces by default.
-         *
-         * @throws IllegalStateException if the builder has already been used.
          */
         @NonNull
         public Builder addSchemas(@NonNull AppSearchSchema... schemas) {
             Objects.requireNonNull(schemas);
+            resetIfBuilt();
             return addSchemas(Arrays.asList(schemas));
         }
 
@@ -201,13 +196,11 @@
          * Adds a collection of {@link AppSearchSchema} objects to the schema.
          *
          * <p>An {@link AppSearchSchema} object represents one type of structured data.
-         *
-         * @throws IllegalStateException if the builder has already been used.
          */
         @NonNull
         public Builder addSchemas(@NonNull Collection<AppSearchSchema> schemas) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Objects.requireNonNull(schemas);
+            resetIfBuilt();
             mSchemas.addAll(schemas);
             return this;
         }
@@ -225,7 +218,6 @@
          * @param schemaType The name of an {@link AppSearchSchema} within the same {@link
          *     SetSchemaRequest}, which will be configured.
          * @param displayed Whether documents of this type will be displayed on system UI surfaces.
-         * @throws IllegalStateException if the builder has already been used.
          */
         // Merged list available from getSchemasNotDisplayedBySystem
         @SuppressLint("MissingGetterMatchingBuilder")
@@ -233,8 +225,7 @@
         public Builder setSchemaTypeDisplayedBySystem(
                 @NonNull String schemaType, boolean displayed) {
             Objects.requireNonNull(schemaType);
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-
+            resetIfBuilt();
             if (displayed) {
                 mSchemasNotDisplayedBySystem.remove(schemaType);
             } else {
@@ -262,7 +253,6 @@
          * @param schemaType The schema type to set visibility on.
          * @param visible Whether the {@code schemaType} will be visible or not.
          * @param packageIdentifier Represents the package that will be granted visibility.
-         * @throws IllegalStateException if the builder has already been used.
          */
         // Merged list available from getSchemasVisibleToPackages
         @SuppressLint("MissingGetterMatchingBuilder")
@@ -273,7 +263,7 @@
                 @NonNull PackageIdentifier packageIdentifier) {
             Objects.requireNonNull(schemaType);
             Objects.requireNonNull(packageIdentifier);
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            resetIfBuilt();
 
             Set<PackageIdentifier> packageIdentifiers = mSchemasVisibleToPackages.get(schemaType);
             if (visible) {
@@ -324,6 +314,7 @@
         public Builder setMigrator(@NonNull String schemaType, @NonNull Migrator migrator) {
             Objects.requireNonNull(schemaType);
             Objects.requireNonNull(migrator);
+            resetIfBuilt();
             mMigrators.put(schemaType, migrator);
             return this;
         }
@@ -352,6 +343,7 @@
         @NonNull
         public Builder setMigrators(@NonNull Map<String, Migrator> migrators) {
             Objects.requireNonNull(migrators);
+            resetIfBuilt();
             mMigrators.putAll(migrators);
             return this;
         }
@@ -369,6 +361,7 @@
          */
         @NonNull
         public Builder setForceOverride(boolean forceOverride) {
+            resetIfBuilt();
             mForceOverride = forceOverride;
             return this;
         }
@@ -391,8 +384,7 @@
          * @param version A positive integer representing the version of the entire set of schemas
          *     represents the version of the whole schema in the {@link AppSearchSession} database,
          *     default version is 1.
-         * @throws IllegalStateException if the version is negative or the builder has already been
-         *     used.
+         * @throws IllegalArgumentException if the version is negative.
          * @see AppSearchSession#setSchema
          * @see Migrator
          * @see SetSchemaRequest.Builder#setMigrator
@@ -400,6 +392,7 @@
         @NonNull
         public Builder setVersion(@IntRange(from = 1) int version) {
             Preconditions.checkArgument(version >= 1, "Version must be a positive number.");
+            resetIfBuilt();
             mVersion = version;
             return this;
         }
@@ -409,12 +402,9 @@
          *
          * @throws IllegalArgumentException if schema types were referenced, but the corresponding
          *     {@link AppSearchSchema} type was never added.
-         * @throws IllegalStateException if the builder has already been used.
          */
         @NonNull
         public SetSchemaRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-
             // Verify that any schema types with display or visibility settings refer to a real
             // schema.
             // Create a copy because we're going to remove from the set for verification purposes.
@@ -440,5 +430,22 @@
                     mForceOverride,
                     mVersion);
         }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                ArrayMap<String, Set<PackageIdentifier>> schemasVisibleToPackages =
+                        new ArrayMap<>(mSchemasVisibleToPackages.size());
+                for (Map.Entry<String, Set<PackageIdentifier>> entry :
+                        mSchemasVisibleToPackages.entrySet()) {
+                    schemasVisibleToPackages.put(entry.getKey(), new ArraySet<>(entry.getValue()));
+                }
+                mSchemasVisibleToPackages = schemasVisibleToPackages;
+
+                mSchemas = new ArraySet<>(mSchemas);
+                mSchemasNotDisplayedBySystem = new ArraySet<>(mSchemasNotDisplayedBySystem);
+                mMigrators = new ArrayMap<>(mMigrators);
+                mBuilt = false;
+            }
+        }
     }
 }
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
index 7ad5fe8..2c75b71 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaResponse.java
@@ -179,81 +179,88 @@
 
     /** Builder for {@link SetSchemaResponse} objects. */
     public static final class Builder {
-        private final ArrayList<MigrationFailure> mMigrationFailures = new ArrayList<>();
-        private final ArrayList<String> mDeletedTypes = new ArrayList<>();
-        private final ArrayList<String> mMigratedTypes = new ArrayList<>();
-        private final ArrayList<String> mIncompatibleTypes = new ArrayList<>();
+        private List<MigrationFailure> mMigrationFailures = new ArrayList<>();
+        private ArrayList<String> mDeletedTypes = new ArrayList<>();
+        private ArrayList<String> mMigratedTypes = new ArrayList<>();
+        private ArrayList<String> mIncompatibleTypes = new ArrayList<>();
         private boolean mBuilt = false;
 
         /** Adds {@link MigrationFailure}s to the list of migration failures. */
         @NonNull
         public Builder addMigrationFailures(
                 @NonNull Collection<MigrationFailure> migrationFailures) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mMigrationFailures.addAll(Objects.requireNonNull(migrationFailures));
+            Objects.requireNonNull(migrationFailures);
+            resetIfBuilt();
+            mMigrationFailures.addAll(migrationFailures);
             return this;
         }
 
         /** Adds a {@link MigrationFailure} to the list of migration failures. */
         @NonNull
         public Builder addMigrationFailure(@NonNull MigrationFailure migrationFailure) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mMigrationFailures.add(Objects.requireNonNull(migrationFailure));
+            Objects.requireNonNull(migrationFailure);
+            resetIfBuilt();
+            mMigrationFailures.add(migrationFailure);
             return this;
         }
 
         /** Adds deletedTypes to the list of deleted schema types. */
         @NonNull
         public Builder addDeletedTypes(@NonNull Collection<String> deletedTypes) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mDeletedTypes.addAll(Objects.requireNonNull(deletedTypes));
+            Objects.requireNonNull(deletedTypes);
+            resetIfBuilt();
+            mDeletedTypes.addAll(deletedTypes);
             return this;
         }
 
         /** Adds one deletedType to the list of deleted schema types. */
         @NonNull
         public Builder addDeletedType(@NonNull String deletedType) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mDeletedTypes.add(Objects.requireNonNull(deletedType));
+            Objects.requireNonNull(deletedType);
+            resetIfBuilt();
+            mDeletedTypes.add(deletedType);
             return this;
         }
 
         /** Adds incompatibleTypes to the list of incompatible schema types. */
         @NonNull
         public Builder addIncompatibleTypes(@NonNull Collection<String> incompatibleTypes) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mIncompatibleTypes.addAll(Objects.requireNonNull(incompatibleTypes));
+            Objects.requireNonNull(incompatibleTypes);
+            resetIfBuilt();
+            mIncompatibleTypes.addAll(incompatibleTypes);
             return this;
         }
 
         /** Adds one incompatibleType to the list of incompatible schema types. */
         @NonNull
         public Builder addIncompatibleType(@NonNull String incompatibleType) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mIncompatibleTypes.add(Objects.requireNonNull(incompatibleType));
+            Objects.requireNonNull(incompatibleType);
+            resetIfBuilt();
+            mIncompatibleTypes.add(incompatibleType);
             return this;
         }
 
         /** Adds migratedTypes to the list of migrated schema types. */
         @NonNull
         public Builder addMigratedTypes(@NonNull Collection<String> migratedTypes) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mMigratedTypes.addAll(Objects.requireNonNull(migratedTypes));
+            Objects.requireNonNull(migratedTypes);
+            resetIfBuilt();
+            mMigratedTypes.addAll(migratedTypes);
             return this;
         }
 
         /** Adds one migratedType to the list of migrated schema types. */
         @NonNull
         public Builder addMigratedType(@NonNull String migratedType) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mMigratedTypes.add(Objects.requireNonNull(migratedType));
+            Objects.requireNonNull(migratedType);
+            resetIfBuilt();
+            mMigratedTypes.add(migratedType);
             return this;
         }
 
         /** Builds a {@link SetSchemaResponse} object. */
         @NonNull
         public SetSchemaResponse build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
             Bundle bundle = new Bundle();
             bundle.putStringArrayList(INCOMPATIBLE_TYPES_FIELD, mIncompatibleTypes);
             bundle.putStringArrayList(DELETED_TYPES_FIELD, mDeletedTypes);
@@ -264,6 +271,16 @@
             // AppSearchSession after we pass SetSchemaResponse via binder.
             return new SetSchemaResponse(bundle, mMigrationFailures);
         }
+
+        private void resetIfBuilt() {
+            if (mBuilt) {
+                mMigrationFailures = new ArrayList<>(mMigrationFailures);
+                mDeletedTypes = new ArrayList<>(mDeletedTypes);
+                mMigratedTypes = new ArrayList<>(mMigratedTypes);
+                mIncompatibleTypes = new ArrayList<>(mIncompatibleTypes);
+                mBuilt = false;
+            }
+        }
     }
 
     /**
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java b/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java
index 502b939..64d4828 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/StorageInfo.java
@@ -19,8 +19,6 @@
 import android.annotation.NonNull;
 import android.os.Bundle;
 
-import com.android.internal.util.Preconditions;
-
 import java.util.Objects;
 
 /** The response class of {@code AppSearchSession#getStorageInfo}. */
@@ -74,39 +72,39 @@
 
     /** Builder for {@link StorageInfo} objects. */
     public static final class Builder {
-        private final Bundle mBundle = new Bundle();
-        private boolean mBuilt = false;
+        private long mSizeBytes;
+        private int mAliveDocumentsCount;
+        private int mAliveNamespacesCount;
 
         /** Sets the size in bytes. */
         @NonNull
         public StorageInfo.Builder setSizeBytes(long sizeBytes) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putLong(SIZE_BYTES_FIELD, sizeBytes);
+            mSizeBytes = sizeBytes;
             return this;
         }
 
         /** Sets the number of alive documents. */
         @NonNull
-        public StorageInfo.Builder setAliveDocumentsCount(int numAliveDocuments) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putInt(ALIVE_DOCUMENTS_COUNT, numAliveDocuments);
+        public StorageInfo.Builder setAliveDocumentsCount(int aliveDocumentsCount) {
+            mAliveDocumentsCount = aliveDocumentsCount;
             return this;
         }
 
         /** Sets the number of alive namespaces. */
         @NonNull
-        public StorageInfo.Builder setAliveNamespacesCount(int numAliveNamespaces) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putInt(ALIVE_NAMESPACES_COUNT, numAliveNamespaces);
+        public StorageInfo.Builder setAliveNamespacesCount(int aliveNamespacesCount) {
+            mAliveNamespacesCount = aliveNamespacesCount;
             return this;
         }
 
         /** Builds a {@link StorageInfo} object. */
         @NonNull
         public StorageInfo build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBuilt = true;
-            return new StorageInfo(mBundle);
+            Bundle bundle = new Bundle();
+            bundle.putLong(SIZE_BYTES_FIELD, mSizeBytes);
+            bundle.putInt(ALIVE_DOCUMENTS_COUNT, mAliveDocumentsCount);
+            bundle.putInt(ALIVE_NAMESPACES_COUNT, mAliveNamespacesCount);
+            return new StorageInfo(bundle);
         }
     }
 }
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 a4188a2..777f9fe 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -29,18 +29,21 @@
 import android.app.appsearch.AppSearchSchema;
 import android.app.appsearch.GenericDocument;
 import android.app.appsearch.GetSchemaResponse;
-import android.app.appsearch.IAppSearchBatchResultCallback;
-import android.app.appsearch.IAppSearchManager;
-import android.app.appsearch.IAppSearchResultCallback;
 import android.app.appsearch.PackageIdentifier;
 import android.app.appsearch.SearchResultPage;
 import android.app.appsearch.SearchSpec;
 import android.app.appsearch.SetSchemaResponse;
 import android.app.appsearch.StorageInfo;
+import android.app.appsearch.aidl.AppSearchBatchResultParcel;
+import android.app.appsearch.aidl.AppSearchResultParcel;
+import android.app.appsearch.aidl.IAppSearchBatchResultCallback;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageStats;
@@ -56,14 +59,15 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalManagerRegistry;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.appsearch.external.localstorage.AppSearchImpl;
 import com.android.server.appsearch.external.localstorage.stats.CallStats;
 import com.android.server.appsearch.stats.LoggerInstanceManager;
 import com.android.server.appsearch.stats.PlatformLogger;
-import com.android.server.usage.StorageStatsManagerInternal;
-import com.android.server.usage.StorageStatsManagerInternal.StorageStatsAugmenter;
+import com.android.server.usage.StorageStatsManagerLocal;
+import com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter;
 
 import com.google.android.icing.proto.PersistType;
 
@@ -120,7 +124,7 @@
         mUserManager = mContext.getSystemService(UserManager.class);
         mLoggerInstanceManager = LoggerInstanceManager.getInstance();
         registerReceivers();
-        LocalServices.getService(StorageStatsManagerInternal.class)
+        LocalManagerRegistry.getManager(StorageStatsManagerLocal.class)
                 .registerStorageStatsAugmenter(new AppSearchStorageStatsAugmenter(), TAG);
     }
 
@@ -230,6 +234,18 @@
         }
     }
 
+    @Override
+    public void onUserStopping(@NonNull TargetUser user) {
+        synchronized (mUnlockedUserIdsLocked) {
+            mUnlockedUserIdsLocked.remove(user.getUserIdentifier());
+            try {
+                mImplInstanceManager.closeAndRemoveAppSearchImplForUser(user.getUserIdentifier());
+            } catch (Throwable t) {
+                Log.e(TAG, "Error handling user stopping.", t);
+            }
+        }
+    }
+
     private void verifyUserUnlocked(int callingUserId) {
         if (isUserLocked(callingUserId)) {
             throw new IllegalStateException("User " + callingUserId + " is locked or not running.");
@@ -869,7 +885,7 @@
         private void invokeCallbackOnResult(
                 IAppSearchResultCallback callback, AppSearchResult<?> result) {
             try {
-                callback.onResult(result);
+                callback.onResult(new AppSearchResultParcel<>(result));
             } catch (RemoteException e) {
                 Log.e(TAG, "Unable to send result to the callback", e);
             }
@@ -877,9 +893,9 @@
 
         /** Invokes the {@link IAppSearchBatchResultCallback} with the result. */
         private void invokeCallbackOnResult(
-                IAppSearchBatchResultCallback callback, AppSearchBatchResult<?, ?> result) {
+                IAppSearchBatchResultCallback callback, AppSearchBatchResult<String, ?> result) {
             try {
-                callback.onResult(result);
+                callback.onResult(new AppSearchBatchResultParcel<>(result));
             } catch (RemoteException e) {
                 Log.e(TAG, "Unable to send result to the callback", e);
             }
@@ -891,8 +907,9 @@
          * <p>The throwable is convert to a {@link AppSearchResult};
          */
         private void invokeCallbackOnError(IAppSearchResultCallback callback, Throwable throwable) {
+            AppSearchResult<?> result = throwableToFailedResult(throwable);
             try {
-                callback.onResult(throwableToFailedResult(throwable));
+                callback.onResult(new AppSearchResultParcel<>(result));
             } catch (RemoteException e) {
                 Log.e(TAG, "Unable to send result to the callback", e);
             }
@@ -905,8 +922,9 @@
          */
         private void invokeCallbackOnError(
                 @NonNull IAppSearchBatchResultCallback callback, @NonNull Throwable throwable) {
+            AppSearchResult<?> result = throwableToFailedResult(throwable);
             try {
-                callback.onSystemError(throwableToFailedResult(throwable));
+                callback.onSystemError(new AppSearchResultParcel<>(result));
             } catch (RemoteException e) {
                 Log.e(TAG, "Unable to send error to the callback", e);
             }
@@ -931,13 +949,15 @@
     // TODO(b/179160886): Cache the previous storage stats.
     private class AppSearchStorageStatsAugmenter implements StorageStatsAugmenter {
         @Override
-        public void augmentStatsForPackage(
+        public void augmentStatsForPackageForUser(
                 @NonNull PackageStats stats,
                 @NonNull String packageName,
-                @UserIdInt int userId,
-                boolean callerHasStatsPermission) {
+                @NonNull UserHandle userHandle,
+                boolean canCallerAccessAllStats) {
             Objects.requireNonNull(stats);
             Objects.requireNonNull(packageName);
+            Objects.requireNonNull(userHandle);
+            int userId = userHandle.getIdentifier();
             try {
                 verifyUserUnlocked(userId);
                 AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
@@ -956,7 +976,7 @@
 
         @Override
         public void augmentStatsForUid(
-                @NonNull PackageStats stats, int uid, boolean callerHasStatsPermission) {
+                @NonNull PackageStats stats, int uid, boolean canCallerAccessAllStats) {
             Objects.requireNonNull(stats);
             int userId = UserHandle.getUserId(uid);
             try {
@@ -967,12 +987,40 @@
                 }
                 AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
                         userId);
-                for (String packageName : packagesForUid) {
-                    stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
+                for (int i = 0; i < packagesForUid.length; i++) {
+                    stats.dataSize +=
+                            impl.getStorageInfoForPackage(packagesForUid[i]).getSizeBytes();
                 }
             } catch (Throwable t) {
                 Log.e(TAG, "Unable to augment storage stats for uid " + uid, t);
             }
         }
+
+        @Override
+        public void augmentStatsForUser(
+                @NonNull PackageStats stats, @NonNull UserHandle userHandle) {
+            // TODO(b/179160886): this implementation could incur many jni calls and a lot of
+            //  in-memory processing from getStorageInfoForPackage. Instead, we can just compute the
+            //  size of the icing dir (or use the overall StorageInfo without interpolating it).
+            Objects.requireNonNull(stats);
+            Objects.requireNonNull(userHandle);
+            int userId = userHandle.getIdentifier();
+            try {
+                verifyUserUnlocked(userId);
+                List<PackageInfo> packagesForUser =
+                        mPackageManager.getInstalledPackagesAsUser(/*flags=*/0, userId);
+                if (packagesForUser == null) {
+                    return;
+                }
+                AppSearchImpl impl =
+                        mImplInstanceManager.getOrCreateAppSearchImpl(mContext, userId);
+                for (int i = 0; i < packagesForUser.size(); i++) {
+                    String packageName = packagesForUser.get(i).packageName;
+                    stats.dataSize += impl.getStorageInfoForPackage(packageName).getSizeBytes();
+                }
+            } catch (Throwable t) {
+                Log.e(TAG, "Unable to augment storage stats for user " + userId, t);
+            }
+        }
     }
 }
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index 94ee830..b815de4 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -117,11 +117,29 @@
      */
     public void removeAppSearchImplForUser(@UserIdInt int userId) {
         synchronized (mInstancesLocked) {
+            // no need to close and persist data to disk since we are removing them now.
             mInstancesLocked.remove(userId);
         }
     }
 
     /**
+     * Close and remove an instance of {@link AppSearchImpl} for the given user.
+     *
+     * <p>All mutation apply to this {@link AppSearchImpl} will be persisted to disk.
+     *
+     * @param userId The multi-user userId of the user that need to be removed.
+     */
+    public void closeAndRemoveAppSearchImplForUser(@UserIdInt int userId) {
+        synchronized (mInstancesLocked) {
+            AppSearchImpl appSearchImpl = mInstancesLocked.get(userId);
+            if (appSearchImpl != null) {
+                appSearchImpl.close();
+                mInstancesLocked.remove(userId);
+            }
+        }
+    }
+
+    /**
      * Gets an instance of AppSearchImpl for the given user.
      *
      * <p>This method should only be called by an initialized SearchSession, which has been already
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
index ecc774c..6b443b3 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
@@ -128,14 +128,14 @@
         return new SearchResult.MatchInfo.Builder(propertyPath)
                 .setExactMatchRange(
                         new SearchResult.MatchRange(
-                                snippetMatchProto.getExactMatchPosition(),
-                                snippetMatchProto.getExactMatchPosition()
-                                        + snippetMatchProto.getExactMatchBytes()))
+                                snippetMatchProto.getExactMatchUtf16Position(),
+                                snippetMatchProto.getExactMatchUtf16Position()
+                                        + snippetMatchProto.getExactMatchUtf16Length()))
                 .setSnippetRange(
                         new SearchResult.MatchRange(
-                                snippetMatchProto.getWindowPosition(),
-                                snippetMatchProto.getWindowPosition()
-                                        + snippetMatchProto.getWindowBytes()))
+                                snippetMatchProto.getWindowUtf16Position(),
+                                snippetMatchProto.getWindowUtf16Position()
+                                        + snippetMatchProto.getWindowUtf16Length()))
                 .build();
     }
 }
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
index cf640c1..ea5263a 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/CallStats.java
@@ -43,13 +43,16 @@
                 CALL_TYPE_SET_SCHEMA,
                 CALL_TYPE_PUT_DOCUMENTS,
                 CALL_TYPE_GET_DOCUMENTS,
-                CALL_TYPE_REMOVE_DOCUMENTS,
+                CALL_TYPE_REMOVE_DOCUMENTS_BY_ID,
                 CALL_TYPE_PUT_DOCUMENT,
                 CALL_TYPE_GET_DOCUMENT,
-                CALL_TYPE_REMOVE_DOCUMENT,
-                CALL_TYPE_QUERY,
+                CALL_TYPE_REMOVE_DOCUMENT_BY_ID,
+                CALL_TYPE_SEARCH,
                 CALL_TYPE_OPTIMIZE,
                 CALL_TYPE_FLUSH,
+                CALL_TYPE_GLOBAL_SEARCH,
+                CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH,
+                CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH,
             })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CallType {}
@@ -59,13 +62,16 @@
     public static final int CALL_TYPE_SET_SCHEMA = 2;
     public static final int CALL_TYPE_PUT_DOCUMENTS = 3;
     public static final int CALL_TYPE_GET_DOCUMENTS = 4;
-    public static final int CALL_TYPE_REMOVE_DOCUMENTS = 5;
+    public static final int CALL_TYPE_REMOVE_DOCUMENTS_BY_ID = 5;
     public static final int CALL_TYPE_PUT_DOCUMENT = 6;
     public static final int CALL_TYPE_GET_DOCUMENT = 7;
-    public static final int CALL_TYPE_REMOVE_DOCUMENT = 8;
-    public static final int CALL_TYPE_QUERY = 9;
+    public static final int CALL_TYPE_REMOVE_DOCUMENT_BY_ID = 8;
+    public static final int CALL_TYPE_SEARCH = 9;
     public static final int CALL_TYPE_OPTIMIZE = 10;
     public static final int CALL_TYPE_FLUSH = 11;
+    public static final int CALL_TYPE_GLOBAL_SEARCH = 12;
+    public static final int CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH = 13;
+    public static final int CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH = 14;
 
     @NonNull private final GeneralStats mGeneralStats;
     @CallType private final int mCallType;
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
new file mode 100644
index 0000000..56a546a
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localstorage.stats;
+
+import android.annotation.NonNull;
+import android.app.appsearch.AppSearchResult;
+
+import java.util.Objects;
+
+/**
+ * Class holds detailed stats for {@link
+ * android.app.appsearch.AppSearchSession#setSchema(SetSchemaRequest)}.
+ *
+ * @hide
+ */
+public final class SetSchemaStats {
+    @NonNull private final String mPackageName;
+
+    @NonNull private final String mDatabase;
+
+    /**
+     * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal
+     * state.
+     */
+    @AppSearchResult.ResultCode private final int mStatusCode;
+
+    private final int mTotalLatencyMillis;
+
+    /** Overall time used for the native function call. */
+    private final int mNativeLatencyMillis;
+
+    /** Number of newly added schema types. */
+    private final int mNewTypeCount;
+
+    /** Number of deleted schema types. */
+    private final int mDeletedTypeCount;
+
+    /** Number of compatible schema type changes. */
+    private final int mCompatibleTypeChangeCount;
+
+    /** Number of index-incompatible schema type changes. */
+    private final int mIndexIncompatibleTypeChangeCount;
+
+    /** Number of backwards-incompatible schema type changes. */
+    private final int mBackwardsIncompatibleTypeChangeCount;
+
+    SetSchemaStats(@NonNull Builder builder) {
+        Objects.requireNonNull(builder);
+        mPackageName = builder.mPackageName;
+        mDatabase = builder.mDatabase;
+        mStatusCode = builder.mStatusCode;
+        mTotalLatencyMillis = builder.mTotalLatencyMillis;
+        mNativeLatencyMillis = builder.mNativeLatencyMillis;
+        mNewTypeCount = builder.mNewTypeCount;
+        mDeletedTypeCount = builder.mDeletedTypeCount;
+        mCompatibleTypeChangeCount = builder.mCompatibleTypeChangeCount;
+        mIndexIncompatibleTypeChangeCount = builder.mIndexIncompatibleTypeChangeCount;
+        mBackwardsIncompatibleTypeChangeCount = builder.mBackwardsIncompatibleTypeChangeCount;
+    }
+
+    /** Returns calling package name. */
+    @NonNull
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    /** Returns calling database name. */
+    @NonNull
+    public String getDatabase() {
+        return mDatabase;
+    }
+
+    /** Returns status of the SetSchema action. */
+    @AppSearchResult.ResultCode
+    public int getStatusCode() {
+        return mStatusCode;
+    }
+
+    /** Returns the total latency of the SetSchema action. */
+    public int getTotalLatencyMillis() {
+        return mTotalLatencyMillis;
+    }
+
+    /** Returns overall time used for the native function call. */
+    public int getNativeLatencyMillis() {
+        return mNativeLatencyMillis;
+    }
+
+    /** Returns number of newly added schema types. */
+    public int getNewTypeCount() {
+        return mNewTypeCount;
+    }
+
+    /** Returns number of deleted schema types. */
+    public int getDeletedTypeCount() {
+        return mDeletedTypeCount;
+    }
+
+    /** Returns number of compatible type changes. */
+    public int getCompatibleTypeChangeCount() {
+        return mCompatibleTypeChangeCount;
+    }
+
+    /**
+     * Returns number of index-incompatible type change.
+     *
+     * <p>An index-incompatible type change is one that affects how pre-existing data should be
+     * searched over, such as modifying the {@code IndexingType} of an existing property.
+     */
+    public int getIndexIncompatibleTypeChangeCount() {
+        return mIndexIncompatibleTypeChangeCount;
+    }
+
+    /**
+     * Returns number of backwards-incompatible type change.
+     *
+     * <p>For details on what constitutes a backward-incompatible type change, please see {@link
+     * android.app.appsearch.SetSchemaRequest}.
+     */
+    public int getBackwardsIncompatibleTypeChangeCount() {
+        return mBackwardsIncompatibleTypeChangeCount;
+    }
+
+    /** Builder for {@link SetSchemaStats}. */
+    public static class Builder {
+        @NonNull final String mPackageName;
+        @NonNull final String mDatabase;
+        @AppSearchResult.ResultCode int mStatusCode;
+        int mTotalLatencyMillis;
+        int mNativeLatencyMillis;
+        int mNewTypeCount;
+        int mDeletedTypeCount;
+        int mCompatibleTypeChangeCount;
+        int mIndexIncompatibleTypeChangeCount;
+        int mBackwardsIncompatibleTypeChangeCount;
+
+        /** Constructor for the {@link Builder}. */
+        public Builder(@NonNull String packageName, @NonNull String database) {
+            mPackageName = Objects.requireNonNull(packageName);
+            mDatabase = Objects.requireNonNull(database);
+        }
+
+        /** Sets the status of the SetSchema action. */
+        @NonNull
+        public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
+            mStatusCode = statusCode;
+            return this;
+        }
+
+        /** Sets total latency for the SetSchema action. */
+        @NonNull
+        public Builder setTotalLatencyMillis(int totalLatencyMillis) {
+            mTotalLatencyMillis = totalLatencyMillis;
+            return this;
+        }
+
+        /** Sets native latency in milliseconds. */
+        @NonNull
+        public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
+            mNativeLatencyMillis = nativeLatencyMillis;
+            return this;
+        }
+
+        /** Sets number of new types. */
+        @NonNull
+        public Builder setNewTypeCount(int newTypeCount) {
+            mNewTypeCount = newTypeCount;
+            return this;
+        }
+
+        /** Sets number of deleted types. */
+        @NonNull
+        public Builder setDeletedTypeCount(int deletedTypeCount) {
+            mDeletedTypeCount = deletedTypeCount;
+            return this;
+        }
+
+        /** Sets number of compatible type changes. */
+        @NonNull
+        public Builder setCompatibleTypeChangeCount(int compatibleTypeChangeCount) {
+            mCompatibleTypeChangeCount = compatibleTypeChangeCount;
+            return this;
+        }
+
+        /** Sets number of index-incompatible type changes. */
+        @NonNull
+        public Builder setIndexIncompatibleTypeChangeCount(int indexIncompatibleTypeChangeCount) {
+            mIndexIncompatibleTypeChangeCount = indexIncompatibleTypeChangeCount;
+            return this;
+        }
+
+        /** Sets number of backwards-incompatible type changes. */
+        @NonNull
+        public Builder setBackwardsIncompatibleTypeChangeCount(
+                int backwardsIncompatibleTypeChangeCount) {
+            mBackwardsIncompatibleTypeChangeCount = backwardsIncompatibleTypeChangeCount;
+            return this;
+        }
+
+        /** Builds a new {@link SetSchemaStats} from the {@link Builder}. */
+        @NonNull
+        public SetSchemaStats build() {
+            return new SetSchemaStats(/* builder= */ this);
+        }
+    }
+}
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 277740f..85d85aa 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-Ic6be29e84e7c6f31cdae37973850bb3395920326
+I0216abecc41d020f16ed8947a9f37b710afd331e
diff --git a/apex/appsearch/testing/Android.bp b/apex/appsearch/testing/Android.bp
index ec64941..5407cb4 100644
--- a/apex/appsearch/testing/Android.bp
+++ b/apex/appsearch/testing/Android.bp
@@ -33,7 +33,7 @@
     visibility: [
         "//frameworks/base/core/tests/coretests",
         "//cts/hostsidetests/appsearch",
-        "//cts/tests/appsearch",
+        "//cts/tests:__subpackages__",
         "//vendor:__subpackages__",
     ],
 }
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
index 941cea9..71b4f36 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/AppSearchSessionShimImpl.java
@@ -17,6 +17,7 @@
 package com.android.server.appsearch.testing;
 
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.appsearch.AppSearchBatchResult;
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchResult;
@@ -37,6 +38,7 @@
 import android.app.appsearch.StorageInfo;
 import android.app.appsearch.exceptions.AppSearchException;
 import android.content.Context;
+import android.os.UserHandle;
 
 import androidx.test.core.app.ApplicationProvider;
 
@@ -58,18 +60,29 @@
     private final AppSearchSession mAppSearchSession;
     private final ExecutorService mExecutor;
 
+    /** Creates the SearchSessionShim with given SearchContext. */
     @NonNull
     public static ListenableFuture<AppSearchSessionShim> createSearchSession(
             @NonNull AppSearchManager.SearchContext searchContext) {
-        return createSearchSession(searchContext, Executors.newCachedThreadPool());
+        Context context = ApplicationProvider.getApplicationContext();
+        return createSearchSession(context, searchContext, Executors.newCachedThreadPool());
     }
 
-    /**  Creates the SearchSession with given ExecutorService. */
+    /** Creates the SearchSessionShim with given SearchContext for the given user. */
     @NonNull
     public static ListenableFuture<AppSearchSessionShim> createSearchSession(
+            @NonNull AppSearchManager.SearchContext searchContext, @UserIdInt int userId) {
+        Context context = ApplicationProvider.getApplicationContext()
+                .createContextAsUser(new UserHandle(userId), /*flags=*/ 0);
+        return createSearchSession(context, searchContext, Executors.newCachedThreadPool());
+    }
+
+    /**  Creates the SearchSession with given Context and ExecutorService. */
+    @NonNull
+    public static ListenableFuture<AppSearchSessionShim> createSearchSession(
+            @NonNull Context context,
             @NonNull AppSearchManager.SearchContext searchContext,
             @NonNull ExecutorService executor) {
-        Context context = ApplicationProvider.getApplicationContext();
         AppSearchManager appSearchManager = context.getSystemService(AppSearchManager.class);
         SettableFuture<AppSearchResult<AppSearchSession>> future = SettableFuture.create();
         appSearchManager.createSearchSession(searchContext, executor, future::set);
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchEmail.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchEmail.java
index 845274d..d28d4ac 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchEmail.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchEmail.java
@@ -165,43 +165,37 @@
         /** Sets the from address of {@link AppSearchEmail} */
         @NonNull
         public Builder setFrom(@NonNull String from) {
-            setPropertyString(KEY_FROM, from);
-            return this;
+            return setPropertyString(KEY_FROM, from);
         }
 
         /** Sets the destination address of {@link AppSearchEmail} */
         @NonNull
         public Builder setTo(@NonNull String... to) {
-            setPropertyString(KEY_TO, to);
-            return this;
+            return setPropertyString(KEY_TO, to);
         }
 
         /** Sets the CC list of {@link AppSearchEmail} */
         @NonNull
         public Builder setCc(@NonNull String... cc) {
-            setPropertyString(KEY_CC, cc);
-            return this;
+            return setPropertyString(KEY_CC, cc);
         }
 
         /** Sets the BCC list of {@link AppSearchEmail} */
         @NonNull
         public Builder setBcc(@NonNull String... bcc) {
-            setPropertyString(KEY_BCC, bcc);
-            return this;
+            return setPropertyString(KEY_BCC, bcc);
         }
 
         /** Sets the subject of {@link AppSearchEmail} */
         @NonNull
         public Builder setSubject(@NonNull String subject) {
-            setPropertyString(KEY_SUBJECT, subject);
-            return this;
+            return setPropertyString(KEY_SUBJECT, subject);
         }
 
         /** Sets the body of {@link AppSearchEmail} */
         @NonNull
         public Builder setBody(@NonNull String body) {
-            setPropertyString(KEY_BODY, body);
-            return this;
+            return setPropertyString(KEY_BODY, body);
         }
 
         /** Builds the {@link AppSearchEmail} object. */
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index cc5e31a..731ba92 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -101,14 +101,15 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.LocalManagerRegistry;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
 import com.android.server.blob.BlobMetadata.Committer;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.usage.StorageStatsManagerInternal;
-import com.android.server.usage.StorageStatsManagerInternal.StorageStatsAugmenter;
+import com.android.server.usage.StorageStatsManagerLocal;
+import com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
@@ -208,7 +209,7 @@
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mStatsManager = getContext().getSystemService(StatsManager.class);
         registerReceivers();
-        LocalServices.getService(StorageStatsManagerInternal.class)
+        LocalManagerRegistry.getManager(StorageStatsManagerLocal.class)
                 .registerStorageStatsAugmenter(new BlobStorageStatsAugmenter(), TAG);
     }
 
@@ -1281,17 +1282,20 @@
 
     private class BlobStorageStatsAugmenter implements StorageStatsAugmenter {
         @Override
-        public void augmentStatsForPackage(@NonNull PackageStats stats, @NonNull String packageName,
-                @UserIdInt int userId, boolean callerHasStatsPermission) {
+        public void augmentStatsForPackageForUser(
+                @NonNull PackageStats stats,
+                @NonNull String packageName,
+                @NonNull UserHandle userHandle,
+                boolean callerHasStatsPermission) {
             final AtomicLong blobsDataSize = new AtomicLong(0);
             forEachSessionInUser(session -> {
                 if (session.getOwnerPackageName().equals(packageName)) {
                     blobsDataSize.getAndAdd(session.getSize());
                 }
-            }, userId);
+            }, userHandle.getIdentifier());
 
             forEachBlob(blobMetadata -> {
-                if (blobMetadata.shouldAttributeToLeasee(packageName, userId,
+                if (blobMetadata.shouldAttributeToLeasee(packageName, userHandle.getIdentifier(),
                         callerHasStatsPermission)) {
                     blobsDataSize.getAndAdd(blobMetadata.getSize());
                 }
@@ -1320,6 +1324,22 @@
 
             stats.dataSize += blobsDataSize.get();
         }
+
+        @Override
+        public void augmentStatsForUser(
+                @NonNull PackageStats stats, @NonNull UserHandle userHandle) {
+            final AtomicLong blobsDataSize = new AtomicLong(0);
+            forEachSessionInUser(session -> {
+                blobsDataSize.getAndAdd(session.getSize());
+            }, userHandle.getIdentifier());
+
+            // TODO(http://b/187460239): Update this to only include blobs available to userId.
+            forEachBlob(blobMetadata -> {
+                blobsDataSize.getAndAdd(blobMetadata.getSize());
+            });
+
+            stats.dataSize += blobsDataSize.get();
+        }
     }
 
     private void forEachSessionInUser(Consumer<BlobStoreSession> consumer, int userId) {
@@ -1900,4 +1920,4 @@
             return BackgroundThread.getHandler();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 01f31e4..b096537 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -138,6 +139,36 @@
     public static final String ACTION_NEXT_ALARM_CLOCK_CHANGED =
             "android.app.action.NEXT_ALARM_CLOCK_CHANGED";
 
+    /**
+     * Broadcast Action: An app is granted the
+     * {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM} permission.
+     *
+     * <p>When the user revokes the {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM}
+     * permission, all alarms scheduled with
+     * {@link #setExact}, {@link #setExactAndAllowWhileIdle} and
+     * {@link #setAlarmClock(AlarmClockInfo, PendingIntent)} will be deleted.
+     *
+     * <p>When the user grants the {@link android.Manifest.permission#SCHEDULE_EXACT_ALARM},
+     * this broadcast will be sent. Applications can reschedule all the necessary alarms when
+     * receiving it.
+     *
+     * <p><em>Note:</em>
+     * Applications are still required to check {@link #canScheduleExactAlarms()}
+     * before using the above APIs after receiving this broadcast,
+     * because it's possible that the permission is already revoked again by the time
+     * applications receive this broadcast.
+     *
+     * <p>This broadcast will be sent to both runtime receivers and manifest receivers.
+     *
+     * <p>This broadcast is sent as a foreground broadcast.
+     * See {@link android.content.Intent#FLAG_RECEIVER_FOREGROUND}.
+     *
+     * <p>When an application receives this broadcast, it's allowed to start a foreground service.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED =
+            "android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED";
+
     /** @hide */
     @UnsupportedAppUsage
     public static final long WINDOW_EXACT = 0;
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index b62ece6..42e953b 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -251,6 +251,12 @@
      * @hide
      */
     public static final int REASON_LOCALE_CHANGED = 206;
+    /**
+     * Broadcast
+     * {@link android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED}
+     * @hide
+     */
+    public static final int REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED = 207;
     /* Reason code range 300-399 are reserved for other internal reasons */
     /**
      * Device idle system allow list, including EXCEPT-IDLE
@@ -338,6 +344,9 @@
      */
     public static final int REASON_MEDIA_SESSION_CALLBACK = 317;
 
+    /** @hide The app requests out-out. */
+    public static final int REASON_OPT_OUT_REQUESTED = 1000;
+
     /**
      * The list of BG-FGS-Launch and temp-allow-list reason code.
      * @hide
@@ -386,6 +395,7 @@
             REASON_TIMEZONE_CHANGED,
             REASON_TIME_CHANGED,
             REASON_LOCALE_CHANGED,
+            REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED,
             REASON_SYSTEM_ALLOW_LISTED,
             REASON_ALARM_MANAGER_ALARM_CLOCK,
             REASON_ALARM_MANAGER_WHILE_IDLE,
@@ -404,6 +414,7 @@
             REASON_EVENT_MMS,
             REASON_SHELL,
             REASON_MEDIA_SESSION_CALLBACK,
+            REASON_OPT_OUT_REQUESTED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ReasonCode {}
@@ -664,6 +675,8 @@
                 return "TIME_CHANGED";
             case REASON_LOCALE_CHANGED:
                 return "LOCALE_CHANGED";
+            case REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED:
+                return "REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED";
             case REASON_SYSTEM_ALLOW_LISTED:
                 return "SYSTEM_ALLOW_LISTED";
             case REASON_ALARM_MANAGER_ALARM_CLOCK:
@@ -700,6 +713,8 @@
                 return "SHELL";
             case REASON_MEDIA_SESSION_CALLBACK:
                 return "MEDIA_SESSION_CALLBACK";
+            case REASON_OPT_OUT_REQUESTED:
+                return "REASON_OPT_OUT_REQUESTED";
             default:
                 return "(unknown:" + reasonCode + ")";
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index b3396c5..0eb2609 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -30,6 +30,7 @@
 import static android.app.AlarmManager.RTC;
 import static android.app.AlarmManager.RTC_WAKEUP;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.os.PowerExemptionManager.REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED;
 import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.PowerWhitelistManager.REASON_ALARM_MANAGER_WHILE_IDLE;
 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -1704,6 +1705,11 @@
                                 if (!hasScheduleExactAlarmInternal(packageName, uid)) {
                                     mHandler.obtainMessage(AlarmHandler.REMOVE_EXACT_ALARMS,
                                             uid, 0, packageName).sendToTarget();
+                                } else {
+                                    // TODO(b/187206399) Make sure this won't be sent, if the app
+                                    // already had the appop previously.
+                                    sendScheduleExactAlarmPermissionStateChangedBroadcast(
+                                            packageName, UserHandle.getUserId(uid));
                                 }
                             }
                         });
@@ -4816,6 +4822,30 @@
         }
     }
 
+    /**
+     * Send {@link AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED} to
+     * the app that is just granted the permission.
+     */
+    private void sendScheduleExactAlarmPermissionStateChangedBroadcast(
+            String packageName, int userId) {
+        final Intent i = new Intent(
+                AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED);
+        i.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+                | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+                | Intent.FLAG_RECEIVER_FOREGROUND);
+        i.setPackage(packageName);
+
+        // We need to allow the app to start a foreground service.
+        // This broadcast is very rare, so we do not cache the BroadcastOptions.
+        final BroadcastOptions opts = BroadcastOptions.makeBasic();
+        opts.setTemporaryAppAllowlist(
+                mActivityManagerInternal.getBootTimeTempAllowListDuration(),
+                TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED, "");
+        getContext().sendBroadcastAsUser(i, UserHandle.of(userId), /*permission*/ null,
+                opts.toBundle());
+    }
+
     private void decrementAlarmCount(int uid, int decrement) {
         int oldCount = 0;
         final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index ebf4ed0..4b081d2 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -180,7 +180,7 @@
             COMPRESS_TIME ? 1 * ONE_MINUTE : 12 * ONE_HOUR,
             COMPRESS_TIME ? 4 * ONE_MINUTE : 24 * ONE_HOUR,
             COMPRESS_TIME ? 16 * ONE_MINUTE : 48 * ONE_HOUR,
-            COMPRESS_TIME ? 32 * ONE_MINUTE : 30 * ONE_DAY
+            COMPRESS_TIME ? 32 * ONE_MINUTE : 45 * ONE_DAY
     };
 
     /** The minimum allowed values for each index in {@link #DEFAULT_ELAPSED_TIME_THRESHOLDS}. */
diff --git a/build/boot/boot-image-profile.txt b/boot/boot-image-profile.txt
similarity index 100%
rename from build/boot/boot-image-profile.txt
rename to boot/boot-image-profile.txt
diff --git a/build/boot/preloaded-classes b/boot/preloaded-classes
similarity index 100%
rename from build/boot/preloaded-classes
rename to boot/preloaded-classes
diff --git a/core/api/current.txt b/core/api/current.txt
index de92fd1..98c2d40 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4404,6 +4404,7 @@
     method public void setWindow(int, long, long, android.app.PendingIntent);
     method public void setWindow(int, long, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
     field public static final String ACTION_NEXT_ALARM_CLOCK_CHANGED = "android.app.action.NEXT_ALARM_CLOCK_CHANGED";
+    field public static final String ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED = "android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED";
     field public static final int ELAPSED_REALTIME = 3; // 0x3
     field public static final int ELAPSED_REALTIME_WAKEUP = 2; // 0x2
     field public static final long INTERVAL_DAY = 86400000L; // 0x5265c00L
@@ -11153,6 +11154,7 @@
     field public static final String ACTION_VIEW = "android.intent.action.VIEW";
     field public static final String ACTION_VIEW_LOCUS = "android.intent.action.VIEW_LOCUS";
     field @RequiresPermission(android.Manifest.permission.START_VIEW_PERMISSION_USAGE) public static final String ACTION_VIEW_PERMISSION_USAGE = "android.intent.action.VIEW_PERMISSION_USAGE";
+    field @RequiresPermission(android.Manifest.permission.START_VIEW_PERMISSION_USAGE) public static final String ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD = "android.intent.action.VIEW_PERMISSION_USAGE_FOR_PERIOD";
     field public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
     field @Deprecated public static final String ACTION_WALLPAPER_CHANGED = "android.intent.action.WALLPAPER_CHANGED";
     field public static final String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
@@ -11205,6 +11207,7 @@
     field public static final String EXTRA_ASSIST_INPUT_HINT_KEYBOARD = "android.intent.extra.ASSIST_INPUT_HINT_KEYBOARD";
     field public static final String EXTRA_ASSIST_PACKAGE = "android.intent.extra.ASSIST_PACKAGE";
     field public static final String EXTRA_ASSIST_UID = "android.intent.extra.ASSIST_UID";
+    field public static final String EXTRA_ATTRIBUTION_TAGS = "android.intent.extra.ATTRIBUTION_TAGS";
     field public static final String EXTRA_AUTO_LAUNCH_SINGLE_CHOICE = "android.intent.extra.AUTO_LAUNCH_SINGLE_CHOICE";
     field public static final String EXTRA_BCC = "android.intent.extra.BCC";
     field public static final String EXTRA_BUG_REPORT = "android.intent.extra.BUG_REPORT";
@@ -11230,6 +11233,7 @@
     field public static final String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP";
     field public static final String EXTRA_DURATION_MILLIS = "android.intent.extra.DURATION_MILLIS";
     field public static final String EXTRA_EMAIL = "android.intent.extra.EMAIL";
+    field public static final String EXTRA_END_TIME = "android.intent.extra.END_TIME";
     field public static final String EXTRA_EXCLUDE_COMPONENTS = "android.intent.extra.EXCLUDE_COMPONENTS";
     field public static final String EXTRA_FROM_STORAGE = "android.intent.extra.FROM_STORAGE";
     field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
@@ -11244,6 +11248,7 @@
     field public static final String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
     field public static final String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
     field public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
+    field public static final String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
     field public static final String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
     field public static final String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
@@ -11266,6 +11271,7 @@
     field @Deprecated public static final String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
+    field public static final String EXTRA_START_TIME = "android.intent.extra.START_TIME";
     field public static final String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
     field public static final String EXTRA_SUSPENDED_PACKAGE_EXTRAS = "android.intent.extra.SUSPENDED_PACKAGE_EXTRAS";
@@ -13078,7 +13084,6 @@
     method public void reportShortcutUsed(String);
     method @WorkerThread public boolean requestPinShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.content.IntentSender);
     method @WorkerThread public boolean setDynamicShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
-    method public void updateShortcutVisibility(@NonNull String, @Nullable byte[], boolean);
     method @WorkerThread public boolean updateShortcuts(@NonNull java.util.List<android.content.pm.ShortcutInfo>);
     field public static final int FLAG_MATCH_CACHED = 8; // 0x8
     field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
@@ -24710,32 +24715,37 @@
     method @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) public int getSubErrorCode();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.media.metrics.PlaybackErrorEvent> CREATOR;
-    field public static final int ERROR_AUDIOTRACK_INIT = 17; // 0x11
-    field public static final int ERROR_AUDIOTRACK_OTHER = 19; // 0x13
-    field public static final int ERROR_AUDIOTRACK_WRITE = 18; // 0x12
-    field public static final int ERROR_DECODER_DECODE = 14; // 0xe
-    field public static final int ERROR_DECODER_INIT = 13; // 0xd
-    field public static final int ERROR_DECODER_OOM = 15; // 0xf
-    field public static final int ERROR_DECODER_OTHER = 16; // 0x10
+    field public static final int ERROR_AUDIO_TRACK_INIT_FAILED = 17; // 0x11
+    field public static final int ERROR_AUDIO_TRACK_OTHER = 19; // 0x13
+    field public static final int ERROR_AUDIO_TRACK_WRITE_FAILED = 18; // 0x12
+    field public static final int ERROR_DECODER_INIT_FAILED = 13; // 0xd
+    field public static final int ERROR_DECODING_FAILED = 14; // 0xe
+    field public static final int ERROR_DECODING_FORMAT_EXCEEDS_CAPABILITIES = 15; // 0xf
+    field public static final int ERROR_DECODING_FORMAT_UNSUPPORTED = 35; // 0x23
+    field public static final int ERROR_DECODING_OTHER = 16; // 0x10
     field public static final int ERROR_DRM_CONTENT_ERROR = 28; // 0x1c
-    field public static final int ERROR_DRM_DISALLOWED = 26; // 0x1a
-    field public static final int ERROR_DRM_LICENSE_ERROR = 25; // 0x19
+    field public static final int ERROR_DRM_DEVICE_REVOKED = 29; // 0x1d
+    field public static final int ERROR_DRM_DISALLOWED_OPERATION = 26; // 0x1a
+    field public static final int ERROR_DRM_LICENSE_ACQUISITION_FAILED = 25; // 0x19
     field public static final int ERROR_DRM_OTHER = 30; // 0x1e
     field public static final int ERROR_DRM_PROVISIONING_FAILED = 24; // 0x18
-    field public static final int ERROR_DRM_REVOKED = 29; // 0x1d
+    field public static final int ERROR_DRM_SCHEME_UNSUPPORTED = 23; // 0x17
     field public static final int ERROR_DRM_SYSTEM_ERROR = 27; // 0x1b
-    field public static final int ERROR_DRM_UNAVAILABLE = 23; // 0x17
-    field public static final int ERROR_MEDIA_MANIFEST = 10; // 0xa
-    field public static final int ERROR_MEDIA_OTHER = 12; // 0xc
-    field public static final int ERROR_MEDIA_PARSER = 11; // 0xb
-    field public static final int ERROR_NETWORK_BAD_STATUS = 5; // 0x5
-    field public static final int ERROR_NETWORK_CLOSED = 8; // 0x8
-    field public static final int ERROR_NETWORK_CONNECT = 4; // 0x4
-    field public static final int ERROR_NETWORK_DNS = 6; // 0x6
-    field public static final int ERROR_NETWORK_OFFLINE = 3; // 0x3
-    field public static final int ERROR_NETWORK_OTHER = 9; // 0x9
-    field public static final int ERROR_NETWORK_TIMEOUT = 7; // 0x7
+    field public static final int ERROR_IO_BAD_HTTP_STATUS = 5; // 0x5
+    field public static final int ERROR_IO_CONNECTION_CLOSED = 8; // 0x8
+    field public static final int ERROR_IO_CONNECTION_TIMEOUT = 7; // 0x7
+    field public static final int ERROR_IO_DNS_FAILED = 6; // 0x6
+    field public static final int ERROR_IO_FILE_NOT_FOUND = 31; // 0x1f
+    field public static final int ERROR_IO_NETWORK_CONNECTION_FAILED = 4; // 0x4
+    field public static final int ERROR_IO_NETWORK_UNAVAILABLE = 3; // 0x3
+    field public static final int ERROR_IO_NO_PERMISSION = 32; // 0x20
+    field public static final int ERROR_IO_OTHER = 9; // 0x9
     field public static final int ERROR_OTHER = 1; // 0x1
+    field public static final int ERROR_PARSING_CONTAINER_MALFORMED = 11; // 0xb
+    field public static final int ERROR_PARSING_CONTAINER_UNSUPPORTED = 34; // 0x22
+    field public static final int ERROR_PARSING_MANIFEST_MALFORMED = 10; // 0xa
+    field public static final int ERROR_PARSING_MANIFEST_UNSUPPORTED = 33; // 0x21
+    field public static final int ERROR_PARSING_OTHER = 12; // 0xc
     field public static final int ERROR_PLAYER_BEHIND_LIVE_WINDOW = 21; // 0x15
     field public static final int ERROR_PLAYER_OTHER = 22; // 0x16
     field public static final int ERROR_PLAYER_REMOTE = 20; // 0x14
@@ -46808,6 +46818,11 @@
     method public void onActionProviderVisibilityChanged(boolean);
   }
 
+  @UiThread public interface AttachedSurfaceControl {
+    method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction);
+    method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
+  }
+
   public final class Choreographer {
     method public static android.view.Choreographer getInstance();
     method public void postFrameCallback(android.view.Choreographer.FrameCallback);
@@ -48534,6 +48549,7 @@
     method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
     method public boolean dispatchCapturedPointerEvent(android.view.MotionEvent);
     method public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public void dispatchCreateViewTranslationRequest(@NonNull java.util.Map<android.view.autofill.AutofillId,long[]>, @NonNull int[], @NonNull android.view.translation.TranslationCapability, @NonNull java.util.List<android.view.translation.ViewTranslationRequest>);
     method public void dispatchDisplayHint(int);
     method public boolean dispatchDragEvent(android.view.DragEvent);
     method protected void dispatchDraw(android.graphics.Canvas);
@@ -48555,7 +48571,6 @@
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public void dispatchProvideAutofillStructure(@NonNull android.view.ViewStructure, int);
     method public void dispatchProvideStructure(android.view.ViewStructure);
-    method public void dispatchRequestTranslation(@NonNull java.util.Map<android.view.autofill.AutofillId,long[]>, @NonNull int[], @NonNull android.view.translation.TranslationCapability, @NonNull java.util.List<android.view.translation.ViewTranslationRequest>);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method public void dispatchScrollCaptureSearch(@NonNull android.graphics.Rect, @NonNull android.graphics.Point, @NonNull java.util.function.Consumer<android.view.ScrollCaptureTarget>);
@@ -48708,6 +48723,7 @@
     method public final int getRight();
     method protected float getRightFadingEdgeStrength();
     method protected int getRightPaddingOffset();
+    method @Nullable public android.view.AttachedSurfaceControl getRootSurfaceControl();
     method public android.view.View getRootView();
     method public android.view.WindowInsets getRootWindowInsets();
     method public float getRotation();
@@ -48752,7 +48768,6 @@
     method @Nullable public android.graphics.drawable.Drawable getVerticalScrollbarThumbDrawable();
     method @Nullable public android.graphics.drawable.Drawable getVerticalScrollbarTrackDrawable();
     method public int getVerticalScrollbarWidth();
-    method @Nullable public android.view.ViewRoot getViewRoot();
     method @Nullable public android.view.translation.ViewTranslationResponse getViewTranslationResponse();
     method public android.view.ViewTreeObserver getViewTreeObserver();
     method public int getVisibility();
@@ -49828,11 +49843,6 @@
     method public android.view.ViewPropertyAnimator zBy(float);
   }
 
-  @UiThread public interface ViewRoot {
-    method public boolean applyTransactionOnDraw(@NonNull android.view.SurfaceControl.Transaction);
-    method @Nullable public android.view.SurfaceControl.Transaction buildReparentTransaction(@NonNull android.view.SurfaceControl);
-  }
-
   public abstract class ViewStructure {
     ctor public ViewStructure();
     method public abstract int addChildCount(int);
@@ -50019,6 +50029,7 @@
     method @ColorInt public int getNavigationBarDividerColor();
     method public android.transition.Transition getReenterTransition();
     method public android.transition.Transition getReturnTransition();
+    method @Nullable public android.view.AttachedSurfaceControl getRootSurfaceControl();
     method public android.transition.Transition getSharedElementEnterTransition();
     method public android.transition.Transition getSharedElementExitTransition();
     method public android.transition.Transition getSharedElementReenterTransition();
@@ -50028,7 +50039,6 @@
     method @NonNull public java.util.List<android.graphics.Rect> getSystemGestureExclusionRects();
     method public long getTransitionBackgroundFadeDuration();
     method public android.transition.TransitionManager getTransitionManager();
-    method @Nullable public android.view.ViewRoot getViewRoot();
     method public abstract int getVolumeControlStream();
     method public android.view.WindowManager getWindowManager();
     method public final android.content.res.TypedArray getWindowStyle();
@@ -52982,7 +52992,7 @@
     method @NonNull public android.view.translation.TranslationRequestValue getValue(@NonNull String);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.ViewTranslationRequest> CREATOR;
-    field public static final String ID_TEXT = "text";
+    field public static final String ID_TEXT = "android:text";
   }
 
   public static final class ViewTranslationRequest.Builder {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 96a23b2..62ffac7 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2399,12 +2399,9 @@
     field public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
     field public static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
     field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
-    field @RequiresPermission(android.Manifest.permission.START_VIEW_PERMISSION_USAGE) public static final String ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD = "android.intent.action.VIEW_PERMISSION_USAGE_FOR_PERIOD";
     field public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
     field public static final String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
-    field public static final String EXTRA_ATTRIBUTION_TAGS = "android.intent.extra.ATTRIBUTION_TAGS";
     field public static final String EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE";
-    field public static final String EXTRA_END_TIME = "android.intent.extra.END_TIME";
     field public static final String EXTRA_FORCE_FACTORY_RESET = "android.intent.extra.FORCE_FACTORY_RESET";
     field public static final String EXTRA_INSTANT_APP_ACTION = "android.intent.extra.INSTANT_APP_ACTION";
     field public static final String EXTRA_INSTANT_APP_BUNDLES = "android.intent.extra.INSTANT_APP_BUNDLES";
@@ -2416,13 +2413,11 @@
     field public static final String EXTRA_LONG_VERSION_CODE = "android.intent.extra.LONG_VERSION_CODE";
     field public static final String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
     field public static final String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
-    field public static final String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
     field public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
     field public static final String EXTRA_REASON = "android.intent.extra.REASON";
     field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
     field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
     field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
-    field public static final String EXTRA_START_TIME = "android.intent.extra.START_TIME";
     field public static final String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
     field public static final String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
     field public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 67108864; // 0x4000000
@@ -14919,6 +14914,7 @@
 
   public static interface WebViewProvider.ViewDelegate {
     method public default void autofill(android.util.SparseArray<android.view.autofill.AutofillValue>);
+    method public default void dispatchCreateViewTranslationRequest(@NonNull java.util.Map<android.view.autofill.AutofillId,long[]>, @NonNull int[], @Nullable android.view.translation.TranslationCapability, @NonNull java.util.List<android.view.translation.ViewTranslationRequest>);
     method public boolean dispatchKeyEvent(android.view.KeyEvent);
     method public android.view.View findFocus(android.view.View);
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index d366e35d..f458107 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -50,6 +50,10 @@
     field public static final String UNDEFINED = "android.permission-group.UNDEFINED";
   }
 
+  public static final class R.attr {
+    field public static final int requestForegroundServiceExemption;
+  }
+
   public static final class R.bool {
     field public static final int config_assistantOnTopOfDream = 17891333; // 0x1110005
     field public static final int config_perDisplayFocusEnabled = 17891332; // 0x1110004
@@ -452,7 +456,7 @@
     method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceNetworkLogs();
     method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void forceRemoveActiveAdmin(@NonNull android.content.ComponentName, int);
     method @RequiresPermission(android.Manifest.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS) public long forceSecurityLogs();
-    method public void forceUpdateUserSetupComplete();
+    method public void forceUpdateUserSetupComplete(int);
     method @NonNull public java.util.Set<java.lang.String> getDefaultCrossProfilePackages();
     method @NonNull public java.util.Set<java.lang.String> getDisallowedSystemApps(@NonNull android.content.ComponentName, int, @NonNull String);
     method public long getLastBugReportRequestTime();
@@ -806,6 +810,7 @@
   }
 
   public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+    method public boolean hasRequestForegroundServiceExemption();
     method public boolean isPrivilegedApp();
     method public boolean isSystemApp();
     field public static final int PRIVATE_FLAG_PRIVILEGED = 8; // 0x8
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2dcdd07..c6847aa 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5662,11 +5662,6 @@
                         R.dimen.call_notification_collapsible_indent);
             }
             big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode);
-            if (p.mCallStyleActions) {
-                // Use "wrap_content" (unlike normal emphasized mode) and allow prioritizing the
-                // required actions (Answer, Decline, and Hang Up).
-                big.setBoolean(R.id.actions, "setPrioritizedWrapMode", true);
-            }
             if (numActions > 0 && !p.mHideActions) {
                 big.setViewVisibility(R.id.actions_container, View.VISIBLE);
                 big.setViewVisibility(R.id.actions, View.VISIBLE);
@@ -5683,7 +5678,7 @@
                         // Clear the drawable
                         button.setInt(R.id.action0, "setBackgroundResource", 0);
                     }
-                    if (p.mCallStyleActions && i > 0) {
+                    if (emphazisedMode && i > 0) {
                         // Clear start margin from non-first buttons to reduce the gap between them.
                         //  (8dp remaining gap is from all buttons' standard 4dp inset).
                         button.setViewLayoutMarginDimen(R.id.action0, RemoteViews.MARGIN_START, 0);
@@ -6103,26 +6098,21 @@
                 // change the background bgColor
                 CharSequence title = action.title;
                 ColorStateList[] outResultColor = new ColorStateList[1];
-                int background = getBackgroundColor(p);
+                int background = getSecondaryAccentColor(p);
                 if (isLegacy()) {
                     title = ContrastColorUtil.clearColorSpans(title);
                 } else {
                     title = ensureColorSpanContrast(title, background, outResultColor);
                 }
                 button.setTextViewText(R.id.action0, processTextSpans(title));
-                final int textColor;
                 boolean hasColorOverride = outResultColor[0] != null;
                 if (hasColorOverride) {
                     // There's a span spanning the full text, let's take it and use it as the
                     // background color
                     background = outResultColor[0].getDefaultColor();
-                    textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
-                            background, mInNightMode);
-                } else if (mTintActionButtons && !mInNightMode && !isBackgroundColorized(p)) {
-                    textColor = getAccentColor(p);
-                } else {
-                    textColor = getPrimaryTextColor(p);
                 }
+                final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
+                        background, mInNightMode);
                 button.setTextColor(R.id.action0, textColor);
                 // We only want about 20% alpha for the ripple
                 final int rippleColor = (textColor & 0x00ffffff) | 0x33000000;
@@ -6130,11 +6120,10 @@
                         ColorStateList.valueOf(rippleColor));
                 button.setColorStateList(R.id.action0, "setButtonBackground",
                         ColorStateList.valueOf(background));
-                button.setBoolean(R.id.action0, "setHasStroke", !hasColorOverride);
                 if (p.mCallStyleActions) {
                     button.setImageViewIcon(R.id.action0, action.getIcon());
                     boolean priority = action.getExtras().getBoolean(CallStyle.KEY_ACTION_PRIORITY);
-                    button.setBoolean(R.id.action0, "setWrapModePriority", priority);
+                    button.setBoolean(R.id.action0, "setIsPriority", priority);
                     int minWidthDimen =
                             priority ? R.dimen.call_notification_system_action_min_width : 0;
                     button.setIntDimen(R.id.action0, "setMinimumWidth", minWidthDimen);
@@ -6320,6 +6309,22 @@
         }
 
         /**
+         * Gets the secondary accent color for colored UI elements.  If we're tinting with the theme
+         * accent, this is the theme accent color, otherwise this would be identical to
+         * {@link #getSmallIconColor(StandardTemplateParams)}.
+         */
+        private @ColorInt int getSecondaryAccentColor(StandardTemplateParams p) {
+            if (isBackgroundColorized(p)) {
+                return getSecondaryTextColor(p);
+            }
+            int color = obtainThemeColor(R.attr.colorAccentSecondary, COLOR_INVALID);
+            if (color != COLOR_INVALID) {
+                return color;
+            }
+            return getContrastColor(p);
+        }
+
+        /**
          * Gets the "surface protection" color from the theme, or a variant of the normal background
          * color when colorized, or when not using theme color tints.
          */
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java
index ad90364..e90bf86 100644
--- a/core/java/android/app/Presentation.java
+++ b/core/java/android/app/Presentation.java
@@ -37,7 +37,8 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams.WindowType;
 
-import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
 /**
  * Base class for presentations.
  * <p>
@@ -153,7 +154,7 @@
 
     private final Display mDisplay;
     private final DisplayManager mDisplayManager;
-    private final Handler mHandler = new Handler(Preconditions.checkNotNull(Looper.myLooper(),
+    private final Handler mHandler = new Handler(Objects.requireNonNull(Looper.myLooper(),
             "Presentation must be constructed on a looper thread."));
 
     /**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 02e64b8..38b19ae 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -11974,15 +11974,14 @@
 
     /**
      * @hide
-     * Force update user setup completed status.
+     * Force update user setup completed status for the given {@code userId}.
      * @throws {@link SecurityException} if the caller has no
-     *         {@code android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS} or the caller is
-     *         not {@link UserHandle#SYSTEM_USER}
+     *         {@code android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}.
      */
     @TestApi
-    public void forceUpdateUserSetupComplete() {
+    public void forceUpdateUserSetupComplete(@UserIdInt int userId) {
         try {
-            mService.forceUpdateUserSetupComplete();
+            mService.forceUpdateUserSetupComplete(userId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 9f76bd1..db2fc0d 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -406,7 +406,7 @@
     boolean isDeviceProvisioningConfigApplied();
     void setDeviceProvisioningConfigApplied();
 
-    void forceUpdateUserSetupComplete();
+    void forceUpdateUserSetupComplete(int userId);
 
     void setBackupServiceEnabled(in ComponentName admin, boolean enabled);
     boolean isBackupServiceEnabled(in ComponentName admin);
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 1cf4567..8c59982 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -189,6 +189,7 @@
      * detected.
      * <li> {@code eio} indicates that an I/O error will be returned for an attempt to read
      * corrupted data blocks.
+     * <li> {@code disabled} indicates that integrity check is disabled.
      * For details see Verified Boot documentation.
      */
     public static final int TAG_OS_STARTUP = SecurityLogTags.SECURITY_OS_STARTUP;
@@ -344,7 +345,7 @@
     public static final int TAG_WIPE_FAILURE = SecurityLogTags.SECURITY_WIPE_FAILED;
 
     /**
-     * Indicates that an authentication key was generated. The log entry contains the following
+     * Indicates that a cryptographic key was generated. The log entry contains the following
      * information about the event, encapsulated in an {@link Object} array and accessible via
      * {@link SecurityEvent#getData()}:
      * <li> [0] result ({@code Integer}, 0 if operation failed, 1 if succeeded)
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 0ca6d74..4032663 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1770,13 +1770,13 @@
      *
      * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
      * with the UUIDs supported by the remote end. If there is an error
-     * in getting the SDP records or if the process takes a long time,
-     * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently
-     * present in the cache. Clients should use the {@link #getUuids} to get UUIDs
+     * in getting the SDP records or if the process takes a long time, or the device is bonding and
+     * we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the UUIDs that is
+     * currently present in the cache. Clients should use the {@link #getUuids} to get UUIDs
      * if service discovery is not to be performed.
      *
      * @return False if the check fails, True if the process of initiating an ACL connection
-     * to the remote device was started.
+     * to the remote device was started or cached UUIDs will be broadcast.
      */
     @RequiresLegacyBluetoothPermission
     @RequiresBluetoothConnectPermission
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index c5c4277..dfef47d 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -586,6 +586,10 @@
          * @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
          */
         public Builder setDeviceAddress(String deviceAddress) {
+            if (deviceAddress == null) {
+                mDeviceAddress = deviceAddress;
+                return this;
+            }
             return setDeviceAddress(deviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC);
         }
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7c7cfdb..bbb49fb 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2022,12 +2022,9 @@
      * <p>
      * Output: Nothing.
      * </p>
-     *
-     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     @RequiresPermission(android.Manifest.permission.START_VIEW_PERMISSION_USAGE)
-    @SystemApi
     public static final String ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD =
             "android.intent.action.VIEW_PERMISSION_USAGE_FOR_PERIOD";
 
@@ -2188,12 +2185,7 @@
      * <p>
      * Type: String
      * </p>
-     *
-     * E.g. {@link android.Manifest.permission_group.CONTACTS}
-     *
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_PERMISSION_GROUP_NAME =
             "android.intent.extra.PERMISSION_GROUP_NAME";
 
@@ -5342,28 +5334,19 @@
      * {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
      *
      * E.g. an attribution tag could be location_provider, com.google.android.gms.*, etc.
-     *
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_ATTRIBUTION_TAGS = "android.intent.extra.ATTRIBUTION_TAGS";
 
     /**
      * A long representing the start timestamp (epoch time in millis) of the permission usage
      * when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
-     *
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_START_TIME = "android.intent.extra.START_TIME";
 
     /**
      * A long representing the end timestamp (epoch time in millis) of the permission usage when
      * used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
-     *
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_END_TIME = "android.intent.extra.END_TIME";
 
     /**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a3e0473..8b0e992 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -778,9 +778,18 @@
      */
     public static final int PRIVATE_FLAG_EXT_PROFILEABLE = 1 << 0;
 
+    /**
+     * Value for {@link #privateFlagsExt}: whether this application has requested
+     * exemption from the foreground service restriction introduced in S
+     * (https://developer.android.com/about/versions/12/foreground-services).
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION = 1 << 1;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PRIVATE_FLAG_EXT_" }, value = {
             PRIVATE_FLAG_EXT_PROFILEABLE,
+            PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ApplicationInfoPrivateFlagsExt {}
@@ -2445,6 +2454,17 @@
     }
 
     /**
+     * @return whether the app has requested exemption from the foreground service restrictions.
+     * This does not take any affect for now.
+     * @hide
+     */
+    @TestApi
+    public boolean hasRequestForegroundServiceExemption() {
+        return (privateFlagsExt
+                & ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION) != 0;
+    }
+
+    /**
      * @hide
      */
     @Override protected ApplicationInfo getApplicationInfo() {
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 9d381ef..804a06b 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -81,7 +81,4 @@
     AndroidFuture<ParceledListSlice> getShortcuts(String packageName, int matchFlags, int userId);
 
     AndroidFuture pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId);
-
-    AndroidFuture updateShortcutVisibility(String callingPkg, String packageName,
-            in byte[] certificate, in boolean visible, int userId);
 }
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 2a36c11..d77fa91 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -40,7 +40,6 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.infra.AndroidFuture;
@@ -790,23 +789,6 @@
         }
     }
 
-    /**
-     * Granting another app the access to the shortcuts you own. You must provide the package name
-     * and their SHA256 certificate digest in order to granting the access.
-     *
-     * Once granted, the other app can retain a copy of all the shortcuts you own when calling
-     * {@link LauncherApps#getShortcuts(LauncherApps.ShortcutQuery, UserHandle)}.
-     */
-    public void updateShortcutVisibility(@NonNull final String packageName,
-            @Nullable final byte[] certificate, final boolean visible) {
-        try {
-            getFutureOrThrow(mService.updateShortcutVisibility(mContext.getPackageName(),
-                    packageName, certificate, visible, injectMyUserId()));
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
     private static <T> T getFutureOrThrow(@NonNull AndroidFuture<T> future) {
         try {
             return future.get();
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 980f10d..a9d70c5 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -397,7 +397,7 @@
         }
 
         // CompatibilityMode is global state.
-        if (!ParsingPackageUtils.sCompatibilityModeEnabled) {
+        if (!android.content.pm.PackageParser.sCompatibilityModeEnabled) {
             ai.disableCompatibilityMode();
         }
 
@@ -806,7 +806,9 @@
     public static int appInfoPrivateFlagsExt(ParsingPackageRead pkg) {
         // @formatter:off
         int privateFlagsExt =
-                flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE);
+                flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE)
+                | flag(pkg.hasRequestForegroundServiceExemption(),
+                        ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION);
         // @formatter:on
         return privateFlagsExt;
     }
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index cea50cb..2413e6d 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -338,6 +338,8 @@
 
     ParsingPackage setTheme(int theme);
 
+    ParsingPackage setRequestForegroundServiceExemption(boolean requestForegroundServiceExemption);
+
     ParsingPackage setUpgradeKeySets(@NonNull Set<String> upgradeKeySets);
 
     ParsingPackage setUse32BitAbi(boolean use32BitAbi);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 7114886..b0342aa 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -464,6 +464,7 @@
                 CROSS_PROFILE,
                 ENABLED,
                 DISALLOW_PROFILING,
+                REQUEST_FOREGROUND_SERVICE_EXEMPTION,
         })
         public @interface Values {}
         private static final long EXTERNAL_STORAGE = 1L;
@@ -512,6 +513,7 @@
         private static final long CROSS_PROFILE = 1L << 43;
         private static final long ENABLED = 1L << 44;
         private static final long DISALLOW_PROFILING = 1L << 45;
+        private static final long REQUEST_FOREGROUND_SERVICE_EXEMPTION = 1L << 46;
     }
 
     private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2199,6 +2201,11 @@
     }
 
     @Override
+    public boolean hasRequestForegroundServiceExemption() {
+        return getBoolean(Booleans.REQUEST_FOREGROUND_SERVICE_EXEMPTION);
+    }
+
+    @Override
     public ParsingPackageImpl setBaseRevisionCode(int value) {
         baseRevisionCode = value;
         return this;
@@ -2420,6 +2427,11 @@
     }
 
     @Override
+    public ParsingPackageImpl setRequestForegroundServiceExemption(boolean value) {
+        return setBoolean(Booleans.REQUEST_FOREGROUND_SERVICE_EXEMPTION, value);
+    }
+
+    @Override
     public ParsingPackageImpl setUiOptions(int value) {
         uiOptions = value;
         return this;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index 1c2c59f..35a2b9a 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -906,10 +906,15 @@
      */
     @ApplicationInfo.NativeHeapZeroInitialized
     int getNativeHeapZeroInitialized();
-
     @Nullable
     Boolean hasRequestRawExternalStorageAccess();
 
+    /**
+     * @see ApplicationInfo#hasRequestForegroundServiceExemption()
+     * @see R.styleable#AndroidManifest_requestForegroundServiceExemption
+     */
+    boolean hasRequestForegroundServiceExemption();
+
     // TODO(b/135203078): Hide and enforce going through PackageInfoUtils
     ApplicationInfo toAppInfoWithoutState();
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 22d75ef..5d74e74 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -2033,6 +2033,12 @@
                                 .AndroidManifestApplication_requestRawExternalStorageAccess,
                         false));
             }
+            if (sa.hasValue(
+                    R.styleable.AndroidManifestApplication_requestForegroundServiceExemption)) {
+                pkg.setRequestForegroundServiceExemption(sa.getBoolean(R.styleable
+                                .AndroidManifestApplication_requestForegroundServiceExemption,
+                        false));
+            }
         } finally {
             sa.recycle();
         }
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 80b5078..8e3de61 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -21,9 +21,11 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.graphics.ImageFormat;
+import android.hardware.camera2.extension.IAdvancedExtenderImpl;
 import android.hardware.camera2.extension.ICameraExtensionsProxyService;
 import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
 import android.hardware.camera2.extension.IPreviewExtenderImpl;
+import android.hardware.camera2.extension.LatencyRange;
 import android.hardware.camera2.extension.SizeList;
 import android.hardware.camera2.params.ExtensionSessionConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
@@ -220,6 +222,7 @@
         private InitializerFuture mInitFuture = null;
         private ServiceConnection mConnection = null;
         private ICameraExtensionsProxyService mProxy = null;
+        private boolean mSupportsAdvancedExtensions = false;
 
         // Singleton, don't allow construction
         private CameraExtensionManagerGlobal() {}
@@ -245,6 +248,11 @@
                     public void onServiceConnected(ComponentName component, IBinder binder) {
                         mProxy = ICameraExtensionsProxyService.Stub.asInterface(binder);
                         mInitFuture.setStatus(true);
+                        try {
+                            mSupportsAdvancedExtensions = mProxy.advancedExtensionsSupported();
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Remote IPC failed!");
+                        }
                     }
                 };
                 ctx.bindService(intent, mConnection, Context.BIND_AUTO_CREATE |
@@ -334,6 +342,10 @@
             }
         }
 
+        public boolean areAdvancedExtensionsSupported() {
+            return mSupportsAdvancedExtensions;
+        }
+
         public IPreviewExtenderImpl initializePreviewExtension(int extensionType)
                 throws RemoteException {
             synchronized (mLock) {
@@ -355,6 +367,17 @@
                 }
             }
         }
+
+        public IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType)
+                throws RemoteException {
+            synchronized (mLock) {
+                if (mProxy != null) {
+                    return mProxy.initializeAdvancedExtension(extensionType);
+                } else {
+                    return null;
+                }
+            }
+        }
     }
 
     /**
@@ -374,23 +397,60 @@
     /**
      * @hide
      */
+    public static boolean areAdvancedExtensionsSupported() {
+        return CameraExtensionManagerGlobal.get().areAdvancedExtensionsSupported();
+    }
+
+    /**
+     * @hide
+     */
     public static boolean isExtensionSupported(String cameraId, int extensionType,
             CameraCharacteristics chars) {
-        Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders;
+        if (areAdvancedExtensionsSupported()) {
+            try {
+                IAdvancedExtenderImpl extender = initializeAdvancedExtension(extensionType);
+                return extender.isExtensionAvailable(cameraId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to query extension availability! Extension service does not"
+                        + " respond!");
+                return false;
+            }
+        } else {
+            Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders;
+            try {
+                extenders = initializeExtension(extensionType);
+            } catch (IllegalArgumentException e) {
+                return false;
+            }
+
+            try {
+                return extenders.first.isExtensionAvailable(cameraId, chars.getNativeMetadata()) &&
+                        extenders.second.isExtensionAvailable(cameraId, chars.getNativeMetadata());
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to query extension availability! Extension service does not"
+                        + " respond!");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static IAdvancedExtenderImpl initializeAdvancedExtension(@Extension int extensionType) {
+        IAdvancedExtenderImpl extender;
         try {
-            extenders = initializeExtension(extensionType);
-        } catch (IllegalArgumentException e) {
-            return false;
+            extender = CameraExtensionManagerGlobal.get().initializeAdvancedExtension(
+                    extensionType);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to initialize extension: " + extensionType);
         }
 
-        try {
-            return extenders.first.isExtensionAvailable(cameraId, chars.getNativeMetadata()) &&
-                extenders.second.isExtensionAvailable(cameraId, chars.getNativeMetadata());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to query extension availability! Extension service does not"
-                    + " respond!");
-            return false;
+        if (extender == null) {
+            throw new IllegalArgumentException("Unknown extension: " + extensionType);
         }
+
+        return extender;
     }
 
     /**
@@ -487,13 +547,21 @@
                 throw new IllegalArgumentException("Unsupported extension");
             }
 
-            Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
-                    initializeExtension(extension);
             StreamConfigurationMap streamMap = mChars.get(
                     CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
-            extenders.first.init(mCameraId, mChars.getNativeMetadata());
-            return generateSupportedSizes(extenders.first.getSupportedResolutions(),
-                    ImageFormat.PRIVATE, streamMap);
+            if (areAdvancedExtensionsSupported()) {
+                IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
+                extender.init(mCameraId);
+                return generateSupportedSizes(
+                        extender.getSupportedPreviewOutputResolutions(mCameraId),
+                        ImageFormat.PRIVATE, streamMap);
+            } else {
+                Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
+                        initializeExtension(extension);
+                extenders.first.init(mCameraId, mChars.getNativeMetadata());
+                return generateSupportedSizes(extenders.first.getSupportedResolutions(),
+                        ImageFormat.PRIVATE, streamMap);
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to query the extension supported sizes! Extension service does"
                     + " not respond!");
@@ -536,31 +604,47 @@
                     throw new IllegalArgumentException("Unsupported extension");
                 }
 
-                Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
-                        initializeExtension(extension);
                 StreamConfigurationMap streamMap = mChars.get(
                         CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
-                if (format == ImageFormat.YUV_420_888) {
-                    extenders.second.init(mCameraId, mChars.getNativeMetadata());
-                    if (extenders.second.getCaptureProcessor() == null) {
-                        // Extensions that don't implement any capture processor are limited to
-                        // JPEG only!
-                        return new ArrayList<>();
+                if (areAdvancedExtensionsSupported()) {
+                    switch(format) {
+                        case ImageFormat.YUV_420_888:
+                        case ImageFormat.JPEG:
+                            break;
+                        default:
+                            throw new IllegalArgumentException("Unsupported format: " + format);
                     }
-                    return generateSupportedSizes(extenders.second.getSupportedResolutions(),
-                            format, streamMap);
-                } else if (format == ImageFormat.JPEG) {
-                    extenders.second.init(mCameraId, mChars.getNativeMetadata());
-                    if (extenders.second.getCaptureProcessor() != null) {
-                        // The framework will perform the additional encoding pass on the
-                        // processed YUV_420 buffers.
-                        return generateJpegSupportedSizes(
-                                extenders.second.getSupportedResolutions(), streamMap);
-                    } else {
-                        return generateSupportedSizes(null, format, streamMap);
-                    }
+                    IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
+                    extender.init(mCameraId);
+                    return generateSupportedSizes(extender.getSupportedCaptureOutputResolutions(
+                            mCameraId), format, streamMap);
                 } else {
-                    throw new IllegalArgumentException("Unsupported format: " + format);
+                    if (format == ImageFormat.YUV_420_888) {
+                        Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
+                                initializeExtension(extension);
+                        extenders.second.init(mCameraId, mChars.getNativeMetadata());
+                        if (extenders.second.getCaptureProcessor() == null) {
+                            // Extensions that don't implement any capture processor are limited to
+                            // JPEG only!
+                            return new ArrayList<>();
+                        }
+                        return generateSupportedSizes(extenders.second.getSupportedResolutions(),
+                                format, streamMap);
+                    } else if (format == ImageFormat.JPEG) {
+                        Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
+                                initializeExtension(extension);
+                        extenders.second.init(mCameraId, mChars.getNativeMetadata());
+                        if (extenders.second.getCaptureProcessor() != null) {
+                            // The framework will perform the additional encoding pass on the
+                            // processed YUV_420 buffers.
+                            return generateJpegSupportedSizes(
+                                    extenders.second.getSupportedResolutions(), streamMap);
+                        } else {
+                            return generateSupportedSizes(null, format, streamMap);
+                        }
+                    } else {
+                        throw new IllegalArgumentException("Unsupported format: " + format);
+                    }
                 }
             } finally {
                 unregisterClient(clientId);
@@ -608,6 +692,23 @@
             if (!isExtensionSupported(mCameraId, extension, mChars)) {
                 throw new IllegalArgumentException("Unsupported extension");
             }
+
+            if (areAdvancedExtensionsSupported()) {
+                IAdvancedExtenderImpl extender = initializeAdvancedExtension(extension);
+                extender.init(mCameraId);
+                android.hardware.camera2.extension.Size sz =
+                        new android.hardware.camera2.extension.Size();
+                sz.width = captureOutputSize.getWidth();
+                sz.height = captureOutputSize.getHeight();
+                LatencyRange latencyRange = extender.getEstimatedCaptureLatencyRange(mCameraId,
+                        sz, format);
+                if (latencyRange != null) {
+                    return new Range(latencyRange.min, latencyRange.max);
+                }
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to query the extension capture latency! Extension service does"
+                    + " not respond!");
         } finally {
             unregisterClient(clientId);
         }
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 6ff68c1..d32341f 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -230,6 +230,33 @@
     }
 
     /**
+     * Takes ownership of the passed-in properties object
+     *
+     * <p>For internal use only</p>
+     * @hide
+     */
+    public CaptureResult(String cameraId, CameraMetadataNative results, CaptureRequest parent,
+            int requestId, long frameNumber) {
+        if (results == null) {
+            throw new IllegalArgumentException("results was null");
+        }
+
+        if (parent == null) {
+            throw new IllegalArgumentException("parent was null");
+        }
+
+        mResults = CameraMetadataNative.move(results);
+        if (mResults.isEmpty()) {
+            throw new AssertionError("Results must not be empty");
+        }
+        setNativeInstance(mResults);
+        mCameraId = cameraId;
+        mRequest = parent;
+        mSequenceId = requestId;
+        mFrameNumber = frameNumber;
+    }
+
+    /**
      * Returns a copy of the underlying {@link CameraMetadataNative}.
      * @hide
      */
diff --git a/core/java/android/hardware/camera2/TotalCaptureResult.java b/core/java/android/hardware/camera2/TotalCaptureResult.java
index df8eecc..ac7f2ca 100644
--- a/core/java/android/hardware/camera2/TotalCaptureResult.java
+++ b/core/java/android/hardware/camera2/TotalCaptureResult.java
@@ -94,6 +94,36 @@
     }
 
     /**
+     * Takes ownership of the passed-in camera metadata and the partial results
+     *
+     * @param partials a list of partial results; {@code null} will be substituted for an empty list
+     * @hide
+     */
+    public TotalCaptureResult(String logicalCameraId, CameraMetadataNative results,
+            CaptureRequest parent, int requestId, long frameNumber, List<CaptureResult> partials,
+            int sessionId, PhysicalCaptureResultInfo[] physicalResults) {
+        super(logicalCameraId, results, parent, requestId, frameNumber);
+
+        if (partials == null) {
+            mPartialResults = new ArrayList<>();
+        } else {
+            mPartialResults = partials;
+        }
+
+        mSessionId = sessionId;
+
+        mPhysicalCaptureResults = new HashMap<String, TotalCaptureResult>();
+        for (PhysicalCaptureResultInfo onePhysicalResult : physicalResults) {
+            TotalCaptureResult physicalResult = new TotalCaptureResult(
+                    onePhysicalResult.getCameraId(), onePhysicalResult.getCameraMetadata(),
+                    parent, requestId, frameNumber, /*partials*/null, sessionId,
+                    new PhysicalCaptureResultInfo[0]);
+            mPhysicalCaptureResults.put(onePhysicalResult.getCameraId(),
+                    physicalResult);
+        }
+    }
+
+    /**
      * Creates a request-less result.
      *
      * <p><strong>For testing only.</strong></p>
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
new file mode 100644
index 0000000..a61bb33
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.extension.Size;
+import android.hardware.camera2.extension.OutputConfigId;
+import android.view.Surface;
+
+/** @hide */
+parcelable CameraOutputConfig
+{
+    Size size;
+    Surface surface;
+    int imageFormat;
+    int capacity;
+
+    const int TYPE_SURFACE = 0;
+    const int TYPE_IMAGEREADER = 1;
+    const int TYPE_MULTIRES_IMAGEREADER = 2;
+    int type;
+
+    OutputConfigId outputId;
+    int surfaceGroupId;
+    String physicalCameraId;
+    List<OutputConfigId> surfaceSharingOutputConfigs;
+}
diff --git a/core/java/android/hardware/camera2/extension/CameraSessionConfig.aidl b/core/java/android/hardware/camera2/extension/CameraSessionConfig.aidl
new file mode 100644
index 0000000..97ce183
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/CameraSessionConfig.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.extension.CameraOutputConfig;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/** @hide */
+parcelable CameraSessionConfig
+{
+    List<CameraOutputConfig> outputConfigs;
+    CameraMetadataNative sessionParameter;
+    int sessionTemplateId;
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl b/core/java/android/hardware/camera2/extension/CaptureFailure.aidl
similarity index 62%
copy from apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
copy to core/java/android/hardware/camera2/extension/CaptureFailure.aidl
index 37ce990..d48696c 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
+++ b/core/java/android/hardware/camera2/extension/CaptureFailure.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright 2020, The Android Open Source Project
+ * 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.
@@ -13,7 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.hardware.camera2.extension;
 
-/** {@hide} */
-parcelable AppSearchResult<ValueType>;
\ No newline at end of file
+import android.hardware.camera2.CaptureRequest;
+
+/** @hide */
+parcelable CaptureFailure
+{
+    CaptureRequest request;
+    int reason;
+    boolean dropped;
+    int sequenceId;
+    long frameNumber;
+    String errorPhysicalCameraId;
+}
diff --git a/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl b/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl
new file mode 100644
index 0000000..f279c59
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/IAdvancedExtenderImpl.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.extension.ISessionProcessorImpl;
+import android.hardware.camera2.extension.LatencyRange;
+import android.hardware.camera2.extension.Size;
+import android.hardware.camera2.extension.SizeList;
+
+/** @hide */
+interface IAdvancedExtenderImpl
+{
+    boolean isExtensionAvailable(in String cameraId);
+    void init(in String cameraId);
+    LatencyRange getEstimatedCaptureLatencyRange(in String cameraId, in Size outputSize,
+            int format);
+    @nullable List<SizeList> getSupportedPreviewOutputResolutions(in String cameraId);
+    @nullable List<SizeList> getSupportedCaptureOutputResolutions(in String cameraId);
+    ISessionProcessorImpl getSessionProcessor();
+}
diff --git a/core/java/android/hardware/camera2/extension/ICameraExtensionsProxyService.aidl b/core/java/android/hardware/camera2/extension/ICameraExtensionsProxyService.aidl
index 2a6d22c..bc29e9a 100644
--- a/core/java/android/hardware/camera2/extension/ICameraExtensionsProxyService.aidl
+++ b/core/java/android/hardware/camera2/extension/ICameraExtensionsProxyService.aidl
@@ -15,6 +15,7 @@
  */
 package android.hardware.camera2.extension;
 
+import android.hardware.camera2.extension.IAdvancedExtenderImpl;
 import android.hardware.camera2.extension.IPreviewExtenderImpl;
 import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
 
@@ -23,6 +24,8 @@
 {
     long registerClient();
     void unregisterClient(long clientId);
+    boolean advancedExtensionsSupported();
     @nullable IPreviewExtenderImpl initializePreviewExtension(int extensionType);
     @nullable IImageCaptureExtenderImpl initializeImageExtension(int extensionType);
+    @nullable IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType);
 }
diff --git a/core/java/android/hardware/camera2/extension/ICaptureCallback.aidl b/core/java/android/hardware/camera2/extension/ICaptureCallback.aidl
new file mode 100644
index 0000000..6ab0ad2
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/ICaptureCallback.aidl
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.extension.Request;
+
+/** @hide */
+interface ICaptureCallback
+{
+    void onCaptureStarted(int captureSequenceId, long timestamp);
+    void onCaptureProcessStarted(int captureSequenceId);
+    void onCaptureFailed(int captureSequenceId);
+    void onCaptureSequenceCompleted(int captureSequenceId);
+    void onCaptureSequenceAborted(int captureSequenceId);
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl b/core/java/android/hardware/camera2/extension/IImageProcessorImpl.aidl
similarity index 61%
copy from apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
copy to core/java/android/hardware/camera2/extension/IImageProcessorImpl.aidl
index 37ce990..f365469 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
+++ b/core/java/android/hardware/camera2/extension/IImageProcessorImpl.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright 2020, The Android Open Source Project
+ * 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.
@@ -13,7 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.hardware.camera2.extension;
 
-/** {@hide} */
-parcelable AppSearchResult<ValueType>;
\ No newline at end of file
+import android.hardware.camera2.extension.OutputConfigId;
+import android.hardware.camera2.extension.ParcelImage;
+
+/** @hide */
+interface IImageProcessorImpl
+{
+    void onNextImageAvailable(in OutputConfigId outputConfigId, in ParcelImage image);
+}
diff --git a/core/java/android/hardware/camera2/extension/IRequestCallback.aidl b/core/java/android/hardware/camera2/extension/IRequestCallback.aidl
new file mode 100644
index 0000000..5f308b7
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/IRequestCallback.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.extension.CaptureFailure;
+import android.hardware.camera2.extension.ParcelCaptureResult;
+import android.hardware.camera2.extension.ParcelTotalCaptureResult;
+
+/** @hide */
+interface IRequestCallback
+{
+    void onCaptureStarted(int requestId, long frameNumber, long timestamp);
+    void onCaptureProgressed(int requestId, in ParcelCaptureResult partialResult);
+    void onCaptureCompleted(int requestId, in ParcelTotalCaptureResult totalCaptureResult);
+    void onCaptureFailed(int requestId, in CaptureFailure captureFailure);
+    void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId);
+    void onCaptureSequenceCompleted(int sequenceId, long frameNumber);
+    void onCaptureSequenceAborted(int sequenceId);
+}
diff --git a/core/java/android/hardware/camera2/extension/IRequestProcessorImpl.aidl b/core/java/android/hardware/camera2/extension/IRequestProcessorImpl.aidl
new file mode 100644
index 0000000..52595a8
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/IRequestProcessorImpl.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.extension.IImageProcessorImpl;
+import android.hardware.camera2.extension.IRequestCallback;
+import android.hardware.camera2.extension.OutputConfigId;
+import android.hardware.camera2.extension.Request;
+
+/** @hide */
+interface IRequestProcessorImpl
+{
+    void setImageProcessor(in OutputConfigId outputConfigId, in IImageProcessorImpl imageProcessor);
+    boolean submit(in Request request, in IRequestCallback callback);
+    boolean submitBurst(in List<Request> requests, in IRequestCallback callback);
+    boolean setRepeating(in Request request, in IRequestCallback callback);
+    void abortCaptures();
+    void stopRepeating();
+}
diff --git a/core/java/android/hardware/camera2/extension/ISessionProcessorImpl.aidl b/core/java/android/hardware/camera2/extension/ISessionProcessorImpl.aidl
new file mode 100644
index 0000000..6fdf4df
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/ISessionProcessorImpl.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.extension.CameraSessionConfig;
+import android.hardware.camera2.extension.ICaptureCallback;
+import android.hardware.camera2.extension.IRequestProcessorImpl;
+import android.hardware.camera2.extension.OutputSurface;
+
+/** @hide */
+interface ISessionProcessorImpl
+{
+    CameraSessionConfig initSession(in String cameraId, in OutputSurface previewSurface,
+            in OutputSurface imageCaptureSurface);
+    void deInitSession();
+    void onCaptureSessionStart(IRequestProcessorImpl requestProcessor);
+    void onCaptureSessionEnd();
+    int startRepeating(in ICaptureCallback callback);
+    void stopRepeating();
+    int startCapture(in ICaptureCallback callback, int jpegRotation, int jpegQuality);
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl b/core/java/android/hardware/camera2/extension/LatencyRange.aidl
similarity index 76%
copy from apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
copy to core/java/android/hardware/camera2/extension/LatencyRange.aidl
index 37ce990..9bedbb0 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
+++ b/core/java/android/hardware/camera2/extension/LatencyRange.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright 2020, The Android Open Source Project
+ * 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.
@@ -13,7 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.hardware.camera2.extension;
 
-/** {@hide} */
-parcelable AppSearchResult<ValueType>;
\ No newline at end of file
+/** @hide */
+parcelable LatencyRange
+{
+    long min;
+    long max;
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl b/core/java/android/hardware/camera2/extension/OutputConfigId.aidl
similarity index 77%
copy from apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
copy to core/java/android/hardware/camera2/extension/OutputConfigId.aidl
index 37ce990..b27f29a 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
+++ b/core/java/android/hardware/camera2/extension/OutputConfigId.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright 2020, The Android Open Source Project
+ * 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.
@@ -13,7 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.hardware.camera2.extension;
 
-/** {@hide} */
-parcelable AppSearchResult<ValueType>;
\ No newline at end of file
+/** @hide */
+parcelable OutputConfigId
+{
+    int id;
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl b/core/java/android/hardware/camera2/extension/OutputSurface.aidl
similarity index 67%
copy from apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
copy to core/java/android/hardware/camera2/extension/OutputSurface.aidl
index 299c9957..8415379 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchResultCallback.aidl
+++ b/core/java/android/hardware/camera2/extension/OutputSurface.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright 2020, The Android Open Source Project
+ * 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.
@@ -13,11 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
+package android.hardware.camera2.extension;
 
-import android.app.appsearch.AppSearchResult;
+import android.hardware.camera2.extension.Size;
+import android.view.Surface;
 
-/** {@hide} */
-oneway interface IAppSearchResultCallback {
-    void onResult(in AppSearchResult result);
+/** @hide */
+parcelable OutputSurface
+{
+    Surface surface;
+    Size size;
+    int imageFormat;
 }
diff --git a/core/java/android/hardware/camera2/extension/ParcelCaptureResult.aidl b/core/java/android/hardware/camera2/extension/ParcelCaptureResult.aidl
new file mode 100644
index 0000000..f99b256
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/ParcelCaptureResult.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/** @hide */
+parcelable ParcelCaptureResult
+{
+    String cameraId;
+    CameraMetadataNative results;
+    CaptureRequest parent;
+    int sequenceId;
+    long frameNumber;
+}
diff --git a/core/java/android/hardware/camera2/extension/ParcelTotalCaptureResult.aidl b/core/java/android/hardware/camera2/extension/ParcelTotalCaptureResult.aidl
new file mode 100644
index 0000000..8021a57
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/ParcelTotalCaptureResult.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.extension.ParcelCaptureResult;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
+
+/** @hide */
+parcelable ParcelTotalCaptureResult
+{
+    String logicalCameraId;
+    CameraMetadataNative results;
+    CaptureRequest parent;
+    int sequenceId;
+    long frameNumber;
+    List<ParcelCaptureResult> partials;
+    int sessionId;
+    List<PhysicalCaptureResultInfo> physicalResult;
+}
diff --git a/core/java/android/hardware/camera2/extension/Request.aidl b/core/java/android/hardware/camera2/extension/Request.aidl
new file mode 100644
index 0000000..d9934dc
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/Request.aidl
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.extension;
+
+import android.hardware.camera2.extension.OutputConfigId;
+import android.hardware.camera2.impl.CameraMetadataNative;
+
+/** @hide */
+parcelable Request
+{
+    List<OutputConfigId> targetOutputConfigIds;
+    CameraMetadataNative parameters;
+    int templateId;
+    int requestId;
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
new file mode 100644
index 0000000..abc487d
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -0,0 +1,917 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.impl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.hardware.camera2.CameraExtensionSession;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.extension.CameraOutputConfig;
+import android.hardware.camera2.extension.CameraSessionConfig;
+import android.hardware.camera2.extension.IAdvancedExtenderImpl;
+import android.hardware.camera2.extension.ICaptureCallback;
+import android.hardware.camera2.extension.IImageProcessorImpl;
+import android.hardware.camera2.extension.IRequestCallback;
+import android.hardware.camera2.extension.IRequestProcessorImpl;
+import android.hardware.camera2.extension.ISessionProcessorImpl;
+import android.hardware.camera2.extension.OutputConfigId;
+import android.hardware.camera2.extension.OutputSurface;
+import android.hardware.camera2.extension.ParcelCaptureResult;
+import android.hardware.camera2.extension.ParcelImage;
+import android.hardware.camera2.extension.ParcelTotalCaptureResult;
+import android.hardware.camera2.extension.Request;
+import android.hardware.camera2.params.ExtensionSessionConfiguration;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
+import android.hardware.camera2.utils.SurfaceUtils;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSession {
+    private static final String TAG = "CameraAdvancedExtensionSessionImpl";
+
+    private final Executor mExecutor;
+    private final CameraDevice mCameraDevice;
+    private final long mExtensionClientId;
+    private final Handler mHandler;
+    private final HandlerThread mHandlerThread;
+    private final CameraExtensionSession.StateCallback mCallbacks;
+    private final IAdvancedExtenderImpl mAdvancedExtender;
+    // maps camera outputs to extension output ids
+    private final HashMap<Surface, Integer> mSurfaceIdMap = new HashMap<>();
+    // maps camera extension output ids to camera registered image readers
+    private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
+    private final RequestProcessor mRequestProcessor = new RequestProcessor();
+
+    private Surface mClientRepeatingRequestSurface;
+    private Surface mClientCaptureSurface;
+    private CameraCaptureSession mCaptureSession = null;
+    private ISessionProcessorImpl mSessionProcessor = null;
+
+    private boolean mInitialized;
+
+
+    // Lock to synchronize cross-thread access to device public interface
+    final Object mInterfaceLock = new Object(); // access from this class and Session only!
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.CAMERA)
+    public static CameraAdvancedExtensionSessionImpl createCameraAdvancedExtensionSession(
+            @NonNull CameraDevice cameraDevice, @NonNull Context ctx,
+            @NonNull ExtensionSessionConfiguration config)
+            throws CameraAccessException, RemoteException {
+        long clientId = CameraExtensionCharacteristics.registerClient(ctx);
+        if (clientId < 0) {
+            throw new UnsupportedOperationException("Unsupported extension!");
+        }
+
+        String cameraId = cameraDevice.getId();
+        CameraManager manager = ctx.getSystemService(CameraManager.class);
+        CameraCharacteristics chars = manager.getCameraCharacteristics(cameraId);
+        CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
+                cameraId, chars);
+
+        if (!CameraExtensionCharacteristics.isExtensionSupported(cameraDevice.getId(),
+                config.getExtension(), chars)) {
+            throw new UnsupportedOperationException("Unsupported extension type: " +
+                    config.getExtension());
+        }
+
+        if (config.getOutputConfigurations().isEmpty() ||
+                config.getOutputConfigurations().size() > 2) {
+            throw new IllegalArgumentException("Unexpected amount of output surfaces, received: " +
+                    config.getOutputConfigurations().size() + " expected <= 2");
+        }
+
+        int suitableSurfaceCount = 0;
+        List<Size> supportedPreviewSizes = extensionChars.getExtensionSupportedSizes(
+                config.getExtension(), SurfaceTexture.class);
+        Surface repeatingRequestSurface = CameraExtensionUtils.getRepeatingRequestSurface(
+                config.getOutputConfigurations(), supportedPreviewSizes);
+        if (repeatingRequestSurface != null) {
+            suitableSurfaceCount++;
+        }
+
+        HashMap<Integer, List<Size>> supportedCaptureSizes = new HashMap<>();
+        for (int format : CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS) {
+            List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
+                    config.getExtension(), format);
+            if (supportedSizes != null) {
+                supportedCaptureSizes.put(format, supportedSizes);
+            }
+        }
+        Surface burstCaptureSurface = CameraExtensionUtils.getBurstCaptureSurface(
+                config.getOutputConfigurations(), supportedCaptureSizes);
+        if (burstCaptureSurface != null) {
+            suitableSurfaceCount++;
+        }
+
+        if (suitableSurfaceCount != config.getOutputConfigurations().size()) {
+            throw new IllegalArgumentException("One or more unsupported output surfaces found!");
+        }
+
+        IAdvancedExtenderImpl extender = CameraExtensionCharacteristics.initializeAdvancedExtension(
+                config.getExtension());
+        extender.init(cameraId);
+
+        CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(clientId,
+                extender, cameraDevice, repeatingRequestSurface, burstCaptureSurface,
+                config.getStateCallback(), config.getExecutor());
+        ret.initialize();
+
+        return ret;
+    }
+
+    private CameraAdvancedExtensionSessionImpl(long extensionClientId,
+            @NonNull IAdvancedExtenderImpl extender, @NonNull CameraDevice cameraDevice,
+            @Nullable Surface repeatingRequestSurface, @Nullable Surface burstCaptureSurface,
+            @NonNull CameraExtensionSession.StateCallback callback, @NonNull Executor executor) {
+        mExtensionClientId = extensionClientId;
+        mAdvancedExtender = extender;
+        mCameraDevice = cameraDevice;
+        mCallbacks = callback;
+        mExecutor = executor;
+        mClientRepeatingRequestSurface = repeatingRequestSurface;
+        mClientCaptureSurface = burstCaptureSurface;
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+        mInitialized = false;
+    }
+
+    /**
+     * @hide
+     */
+    public synchronized void initialize() throws CameraAccessException, RemoteException {
+        if (mInitialized) {
+            Log.d(TAG, "Session already initialized");
+            return;
+        }
+
+        OutputSurface previewSurface = initializeParcelable(mClientRepeatingRequestSurface);
+        OutputSurface captureSurface = initializeParcelable(mClientCaptureSurface);
+        mSessionProcessor = mAdvancedExtender.getSessionProcessor();
+        CameraSessionConfig sessionConfig = mSessionProcessor.initSession(mCameraDevice.getId(),
+                previewSurface, captureSurface);
+        List<CameraOutputConfig> outputConfigs = sessionConfig.outputConfigs;
+        // map camera output ids to output configurations
+        HashMap<Integer, OutputConfiguration> cameraOutputs = new HashMap<>();
+        for (CameraOutputConfig output : outputConfigs) {
+            OutputConfiguration cameraOutput = null;
+            switch(output.type) {
+                case CameraOutputConfig.TYPE_SURFACE:
+                    if (output.surface == null) {
+                        Log.w(TAG, "Unsupported client output id: " + output.outputId.id +
+                                ", skipping!");
+                        continue;
+                    }
+                    cameraOutput = new OutputConfiguration(output.surfaceGroupId,
+                            output.surface);
+                    break;
+                case CameraOutputConfig.TYPE_IMAGEREADER:
+                    if ((output.imageFormat == ImageFormat.UNKNOWN) || (output.size.width <= 0) ||
+                            (output.size.height <= 0)) {
+                        Log.w(TAG, "Unsupported client output id: " + output.outputId.id +
+                                ", skipping!");
+                        continue;
+                    }
+                    ImageReader reader = ImageReader.newInstance(output.size.width,
+                            output.size.height, output.imageFormat, output.capacity);
+                    mReaderMap.put(output.outputId.id, reader);
+                    cameraOutput = new OutputConfiguration(output.surfaceGroupId,
+                            reader.getSurface());
+                    break;
+                case CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER:
+                    // TBD
+                default:
+                    throw new IllegalArgumentException("Unsupported output config type: " +
+                            output.type);
+            }
+            cameraOutput.setPhysicalCameraId(output.physicalCameraId);
+            cameraOutputs.put(output.outputId.id, cameraOutput);
+        }
+
+        ArrayList<OutputConfiguration> outputList = new ArrayList<>();
+        for (CameraOutputConfig output : outputConfigs) {
+            if (!cameraOutputs.containsKey(output.outputId.id)) {
+                // Shared surface already removed by a previous iteration
+                continue;
+            }
+            OutputConfiguration outConfig = cameraOutputs.get(output.outputId.id);
+            if ((output.surfaceSharingOutputConfigs != null) &&
+                    !output.surfaceSharingOutputConfigs.isEmpty()) {
+                outConfig.enableSurfaceSharing();
+                for (OutputConfigId outputId : output.surfaceSharingOutputConfigs) {
+                    outConfig.addSurface(cameraOutputs.get(outputId.id).getSurface());
+                    cameraOutputs.remove(outputId.id);
+                }
+            }
+            outputList.add(outConfig);
+            mSurfaceIdMap.put(outConfig.getSurface(), output.outputId.id);
+        }
+
+        SessionConfiguration sessionConfiguration = new SessionConfiguration(
+                SessionConfiguration.SESSION_REGULAR, outputList,
+                new CameraExtensionUtils.HandlerExecutor(mHandler), new SessionStateHandler());
+
+        if ((sessionConfig.sessionParameter != null) &&
+                (!sessionConfig.sessionParameter.isEmpty())) {
+            CaptureRequest.Builder requestBuilder = mCameraDevice.createCaptureRequest(
+                    sessionConfig.sessionTemplateId);
+            CaptureRequest sessionRequest = requestBuilder.build();
+            CameraMetadataNative.update(sessionRequest.getNativeMetadata(),
+                    sessionConfig.sessionParameter);
+            sessionConfiguration.setSessionParameters(sessionRequest);
+        }
+
+        mCameraDevice.createCaptureSession(sessionConfiguration);
+    }
+
+    private static ParcelCaptureResult initializeParcelable(CaptureResult result) {
+        ParcelCaptureResult ret = new ParcelCaptureResult();
+        ret.cameraId = result.getCameraId();
+        ret.results = result.getNativeMetadata();
+        ret.parent = result.getRequest();
+        ret.sequenceId = result.getSequenceId();
+        ret.frameNumber = result.getFrameNumber();
+
+        return ret;
+    }
+
+    private static ParcelTotalCaptureResult initializeParcelable(TotalCaptureResult totalResult) {
+        ParcelTotalCaptureResult ret = new ParcelTotalCaptureResult();
+        ret.logicalCameraId = totalResult.getCameraId();
+        ret.results = totalResult.getNativeMetadata();
+        ret.parent = totalResult.getRequest();
+        ret.sequenceId = totalResult.getSequenceId();
+        ret.frameNumber = totalResult.getFrameNumber();
+        ret.sessionId = totalResult.getSessionId();
+        ret.partials = new ArrayList<>(totalResult.getPartialResults().size());
+        for (CaptureResult partial : totalResult.getPartialResults()) {
+            ret.partials.add(initializeParcelable(partial));
+        }
+        Map<String, TotalCaptureResult> physicalResults =
+                totalResult.getPhysicalCameraTotalResults();
+        ret.physicalResult = new ArrayList<>(physicalResults.size());
+        for (TotalCaptureResult physicalResult : physicalResults.values()) {
+            ret.physicalResult.add(new PhysicalCaptureResultInfo(physicalResult.getCameraId(),
+                    physicalResult.getNativeMetadata()));
+        }
+
+        return ret;
+    }
+
+    private static OutputSurface initializeParcelable(Surface s) {
+        OutputSurface ret = new OutputSurface();
+        if (s != null) {
+            ret.surface = s;
+            ret.size = new android.hardware.camera2.extension.Size();
+            Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
+            ret.size.width = surfaceSize.getWidth();
+            ret.size.height = surfaceSize.getHeight();
+            ret.imageFormat = SurfaceUtils.getSurfaceFormat(s);
+        } else {
+            ret.surface = null;
+            ret.size = new android.hardware.camera2.extension.Size();
+            ret.size.width = -1;
+            ret.size.height = -1;
+            ret.imageFormat = ImageFormat.UNKNOWN;
+        }
+
+        return ret;
+    }
+
+    @Override
+    public @NonNull CameraDevice getDevice() {
+        synchronized (mInterfaceLock) {
+            return mCameraDevice;
+        }
+    }
+
+    @Override
+    public int setRepeatingRequest(@NonNull CaptureRequest request, @NonNull Executor executor,
+            @NonNull ExtensionCaptureCallback listener) throws CameraAccessException {
+        int seqId = -1;
+        synchronized (mInterfaceLock) {
+            if (!mInitialized) {
+                throw new IllegalStateException("Uninitialized component");
+            }
+
+            if (mClientRepeatingRequestSurface == null) {
+                throw new IllegalArgumentException("No registered preview surface");
+            }
+
+            if (!request.containsTarget(mClientRepeatingRequestSurface) ||
+                    (request.getTargets().size() != 1)) {
+                throw new IllegalArgumentException("Invalid repeating request output target!");
+            }
+
+            try {
+                seqId = mSessionProcessor.startRepeating(new RequestCallbackHandler(request,
+                        executor, listener));
+            } catch (RemoteException e) {
+                throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
+                        "Failed to enable repeating request, extension service failed to respond!");
+            }
+        }
+
+        return seqId;
+    }
+
+    @Override
+    public int capture(@NonNull CaptureRequest request,
+            @NonNull Executor executor,
+            @NonNull ExtensionCaptureCallback listener) throws CameraAccessException {
+        int seqId = -1;
+        synchronized (mInterfaceLock) {
+            if (!mInitialized) {
+                throw new IllegalStateException("Uninitialized component");
+            }
+
+            if (mClientCaptureSurface == null) {
+                throw new IllegalArgumentException("No output surface registered for single"
+                        + " requests!");
+            }
+
+            if (!request.containsTarget(mClientCaptureSurface) ||
+                    (request.getTargets().size() != 1)) {
+                throw new IllegalArgumentException("Invalid single capture output target!");
+            }
+
+            try {
+                // This will override the extension capture stage jpeg parameters with the user set
+                // jpeg quality and rotation. This will guarantee that client configured jpeg
+                // parameters always have highest priority.
+                Integer jpegRotation = request.get(CaptureRequest.JPEG_ORIENTATION);
+                if (jpegRotation == null) {
+                    jpegRotation = CameraExtensionUtils.JPEG_DEFAULT_ROTATION;
+                }
+                Byte jpegQuality = request.get(CaptureRequest.JPEG_QUALITY);
+                if (jpegQuality == null) {
+                    jpegQuality = CameraExtensionUtils.JPEG_DEFAULT_QUALITY;
+                }
+
+                seqId = mSessionProcessor.startCapture(new RequestCallbackHandler(request,
+                        executor, listener), jpegRotation, jpegQuality);
+            } catch (RemoteException e) {
+                throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
+                        "Failed to submit capture request, extension service failed to respond!");
+            }
+        }
+
+        return seqId;
+    }
+
+    @Override
+    public void stopRepeating() throws CameraAccessException {
+        synchronized (mInterfaceLock) {
+            if (!mInitialized) {
+                throw new IllegalStateException("Uninitialized component");
+            }
+
+            mCaptureSession.stopRepeating();
+
+            try {
+                mSessionProcessor.stopRepeating();
+            } catch (RemoteException e) {
+               throw new CameraAccessException(CameraAccessException.CAMERA_ERROR,
+                       "Failed to notify about the end of repeating request, extension service"
+                               + " failed to respond!");
+            }
+        }
+    }
+
+    @Override
+    public void close() throws CameraAccessException {
+        synchronized (mInterfaceLock) {
+            if (mInitialized) {
+                try {
+                    mCaptureSession.stopRepeating();
+                    mSessionProcessor.stopRepeating();
+                    mSessionProcessor.onCaptureSessionEnd();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to stop the repeating request or end the session,"
+                            + " , extension service does not respond!") ;
+                }
+                mCaptureSession.close();
+            }
+        }
+    }
+
+    public void release() {
+        synchronized (mInterfaceLock) {
+            mInitialized = false;
+            mHandlerThread.quitSafely();
+
+            if (mSessionProcessor != null) {
+                try {
+                    mSessionProcessor.deInitSession();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to de-initialize session processor, extension service"
+                            + " does not respond!") ;
+                }
+                mSessionProcessor = null;
+            }
+
+            if (mExtensionClientId >= 0) {
+                CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
+            }
+
+            for (ImageReader reader : mReaderMap.values()) {
+                reader.close();
+            }
+            mReaderMap.clear();
+
+            mClientRepeatingRequestSurface = null;
+            mClientCaptureSurface = null;
+        }
+    }
+
+    private void notifyConfigurationFailure() {
+        synchronized (mInterfaceLock) {
+            if (mInitialized) {
+                return;
+            }
+        }
+
+        release();
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mExecutor.execute(
+                    () -> mCallbacks.onConfigureFailed(
+                            CameraAdvancedExtensionSessionImpl.this));
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private class SessionStateHandler extends
+            android.hardware.camera2.CameraCaptureSession.StateCallback {
+        @Override
+        public void onClosed(@NonNull CameraCaptureSession session) {
+            release();
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallbacks.onClosed(
+                       CameraAdvancedExtensionSessionImpl.this));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
+            notifyConfigurationFailure();
+        }
+
+        @Override
+        public void onConfigured(@NonNull CameraCaptureSession session) {
+            boolean status = true;
+            synchronized (mInterfaceLock) {
+                mCaptureSession = session;
+                try {
+                    mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
+                    mInitialized = true;
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to start capture session,"
+                            + " extension service does not respond!");
+                    status = false;
+                    session.close();
+                }
+            }
+
+            if (status) {
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(
+                            () -> mCallbacks.onConfigured(CameraAdvancedExtensionSessionImpl.this));
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            } else {
+                notifyConfigurationFailure();
+            }
+        }
+    }
+
+    private final class RequestCallbackHandler extends ICaptureCallback.Stub {
+        private final CaptureRequest mClientRequest;
+        private final Executor mClientExecutor;
+        private final ExtensionCaptureCallback mClientCallbacks;
+
+        private RequestCallbackHandler(@NonNull CaptureRequest clientRequest,
+                @NonNull Executor clientExecutor,
+                @NonNull ExtensionCaptureCallback clientCallbacks) {
+            mClientRequest = clientRequest;
+            mClientExecutor = clientExecutor;
+            mClientCallbacks = clientCallbacks;
+        }
+
+        @Override
+        public void onCaptureStarted(int captureSequenceId, long timestamp) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mClientExecutor.execute(
+                        () -> mClientCallbacks.onCaptureStarted(
+                                CameraAdvancedExtensionSessionImpl.this, mClientRequest,
+                                timestamp));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void onCaptureProcessStarted(int captureSequenceId) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mClientExecutor.execute(
+                        () -> mClientCallbacks.onCaptureProcessStarted(
+                                CameraAdvancedExtensionSessionImpl.this, mClientRequest));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void onCaptureFailed(int captureSequenceId) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mClientExecutor.execute(
+                        () -> mClientCallbacks.onCaptureFailed(
+                                CameraAdvancedExtensionSessionImpl.this, mClientRequest));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void onCaptureSequenceCompleted(int captureSequenceId) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mClientExecutor.execute(
+                        () -> mClientCallbacks.onCaptureSequenceCompleted(
+                                CameraAdvancedExtensionSessionImpl.this, captureSequenceId));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public void onCaptureSequenceAborted(int captureSequenceId) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mClientExecutor.execute(
+                        () -> mClientCallbacks.onCaptureSequenceAborted(
+                                CameraAdvancedExtensionSessionImpl.this, captureSequenceId));
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    private final class CaptureCallbackHandler extends CameraCaptureSession.CaptureCallback {
+        private final IRequestCallback mCallback;
+
+        public CaptureCallbackHandler(IRequestCallback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public void onCaptureBufferLost(CameraCaptureSession session, CaptureRequest request,
+                Surface target, long frameNumber) {
+            try {
+                if (request.getTag() instanceof Integer) {
+                    Integer requestId = (Integer) request.getTag();
+                    mCallback.onCaptureBufferLost(requestId, frameNumber,
+                            mSurfaceIdMap.get(target));
+                } else {
+                    Log.e(TAG, "Invalid capture request tag!");
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to notify lost capture buffer, extension service doesn't"
+                        + " respond!");
+            }
+        }
+
+        @Override
+        public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
+                TotalCaptureResult result) {
+            try {
+                if (request.getTag() instanceof Integer) {
+                    Integer requestId = (Integer) request.getTag();
+                    mCallback.onCaptureCompleted(requestId, initializeParcelable(result));
+                } else {
+                    Log.e(TAG, "Invalid capture request tag!");
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to notify capture result, extension service doesn't"
+                        + " respond!");
+            }
+        }
+
+        @Override
+        public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
+                CaptureFailure failure) {
+            try {
+                if (request.getTag() instanceof Integer) {
+                    Integer requestId = (Integer) request.getTag();
+                    android.hardware.camera2.extension.CaptureFailure captureFailure =
+                            new android.hardware.camera2.extension.CaptureFailure();
+                    captureFailure.request = request;
+                    captureFailure.reason = failure.getReason();
+                    captureFailure.errorPhysicalCameraId = failure.getPhysicalCameraId();
+                    captureFailure.frameNumber = failure.getFrameNumber();
+                    captureFailure.sequenceId = failure.getSequenceId();
+                    captureFailure.dropped = !failure.wasImageCaptured();
+                    mCallback.onCaptureFailed(requestId, captureFailure);
+                } else {
+                    Log.e(TAG, "Invalid capture request tag!");
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to notify capture failure, extension service doesn't"
+                        + " respond!");
+            }
+        }
+
+        @Override
+        public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
+                CaptureResult partialResult) {
+            try {
+                if (request.getTag() instanceof Integer) {
+                    Integer requestId = (Integer) request.getTag();
+                    mCallback.onCaptureProgressed(requestId, initializeParcelable(partialResult));
+                } else {
+                    Log.e(TAG, "Invalid capture request tag!");
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to notify capture partial result, extension service doesn't"
+                        + " respond!");
+            }
+        }
+
+        @Override
+        public void onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) {
+            try {
+                mCallback.onCaptureSequenceAborted(sequenceId);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to notify aborted sequence, extension service doesn't"
+                        + " respond!");
+            }
+        }
+
+        @Override
+        public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId,
+                long frameNumber) {
+            try {
+                mCallback.onCaptureSequenceCompleted(sequenceId, frameNumber);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to notify sequence complete, extension service doesn't"
+                        + " respond!");
+            }
+        }
+
+        @Override
+        public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
+                long timestamp, long frameNumber) {
+            try {
+                if (request.getTag() instanceof Integer) {
+                    Integer requestId = (Integer) request.getTag();
+                    mCallback.onCaptureStarted(requestId, frameNumber, timestamp);
+                } else {
+                    Log.e(TAG, "Invalid capture request tag!");
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to notify capture started, extension service doesn't"
+                        + " respond!");
+            }
+        }
+    }
+
+    private static final class ImageReaderHandler implements ImageReader.OnImageAvailableListener {
+        private final OutputConfigId mOutputConfigId;
+        private final IImageProcessorImpl mIImageProcessor;
+
+        private ImageReaderHandler(int outputConfigId,
+                IImageProcessorImpl iImageProcessor) {
+            mOutputConfigId = new OutputConfigId();
+            mOutputConfigId.id = outputConfigId;
+            mIImageProcessor = iImageProcessor;
+        }
+
+        @Override
+        public void onImageAvailable(ImageReader reader) {
+            if (mIImageProcessor == null) {
+                return;
+            }
+
+            Image img;
+            try {
+                img = reader.acquireNextImage();
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Failed to acquire image, too many images pending!");
+                return;
+            }
+            if (img == null) {
+                Log.e(TAG, "Invalid image!");
+                return;
+            }
+
+            try {
+                reader.detachImage(img);
+            } catch(Exception e) {
+                Log.e(TAG, "Failed to detach image");
+                img.close();
+                return;
+            }
+
+            ParcelImage parcelImage = new ParcelImage();
+            parcelImage.buffer = img.getHardwareBuffer();
+            if (img.getFenceFd() >= 0) {
+                try {
+                    parcelImage.fence = ParcelFileDescriptor.fromFd(img.getFenceFd());
+                } catch (IOException e) {
+                    Log.e(TAG,"Failed to parcel buffer fence!");
+                }
+            }
+            parcelImage.format = img.getFormat();
+            parcelImage.timestamp = img.getTimestamp();
+            parcelImage.transform = img.getTransform();
+            parcelImage.scalingMode = img.getScalingMode();
+            parcelImage.planeCount = img.getPlaneCount();
+            parcelImage.crop = img.getCropRect();
+
+            try {
+                mIImageProcessor.onNextImageAvailable(mOutputConfigId, parcelImage);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to propagate image buffer on output surface id: " +
+                        mOutputConfigId + " extension service does not respond!");
+            } finally {
+                parcelImage.buffer.close();
+                img.close();
+            }
+        }
+    }
+
+    private final class RequestProcessor extends IRequestProcessorImpl.Stub {
+        @Override
+        public void setImageProcessor(OutputConfigId outputConfigId,
+                IImageProcessorImpl imageProcessor) {
+            synchronized (mInterfaceLock) {
+                if (mReaderMap.containsKey(outputConfigId.id)) {
+                    mReaderMap.get(outputConfigId.id).setOnImageAvailableListener(
+                            new ImageReaderHandler(outputConfigId.id, imageProcessor), mHandler);
+                } else {
+                    Log.e(TAG, "ImageReader with output config id: " + outputConfigId.id +
+                            " not found!");
+                }
+            }
+        }
+
+        @Override
+        public boolean submit(Request request, IRequestCallback callback) {
+            ArrayList<Request> captureList = new ArrayList<>();
+            captureList.add(request);
+            return submitBurst(captureList, callback);
+        }
+
+        @Override
+        public boolean submitBurst(List<Request> requests, IRequestCallback callback) {
+            synchronized (mInterfaceLock) {
+                try {
+                    CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+                    ArrayList<CaptureRequest> captureRequests = new ArrayList<>();
+                    for (Request request : requests) {
+                        captureRequests.add(initializeCaptureRequest(mCameraDevice, request,
+                                mSurfaceIdMap));
+                    }
+                    mCaptureSession.captureBurstRequests(captureRequests,
+                            new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+                } catch (CameraAccessException e) {
+                    Log.e(TAG, "Failed to submit capture requests!");
+                    return false;
+                } catch (IllegalStateException e) {
+                    Log.e(TAG, "Capture session closed!");
+                }
+            }
+
+            return true;
+        }
+
+        @Override
+        public boolean setRepeating(Request request, IRequestCallback callback) {
+            synchronized (mInterfaceLock) {
+                try {
+                    CaptureRequest repeatingRequest = initializeCaptureRequest(mCameraDevice,
+                                request, mSurfaceIdMap);
+                    CaptureCallbackHandler captureCallback = new CaptureCallbackHandler(callback);
+                    mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
+                            new CameraExtensionUtils.HandlerExecutor(mHandler), captureCallback);
+                } catch (CameraAccessException e) {
+                    Log.e(TAG, "Failed to enable repeating request!");
+                    return false;
+                } catch (IllegalStateException e) {
+                    Log.e(TAG, "Capture session closed!");
+                }
+            }
+
+            return true;
+        }
+
+        @Override
+        public void abortCaptures() {
+            synchronized (mInterfaceLock) {
+                try {
+                    mCaptureSession.abortCaptures();
+                } catch (CameraAccessException e) {
+                    Log.e(TAG, "Failed during capture abort!");
+                } catch (IllegalStateException e) {
+                    Log.e(TAG, "Capture session closed!");
+                }
+            }
+        }
+
+        @Override
+        public void stopRepeating() {
+            synchronized (mInterfaceLock) {
+                try {
+                    mCaptureSession.stopRepeating();
+                } catch (CameraAccessException e) {
+                    Log.e(TAG, "Failed during repeating capture stop!");
+                } catch (IllegalStateException e) {
+                    Log.e(TAG, "Capture session closed!");
+                }
+            }
+        }
+    }
+
+    private static CaptureRequest initializeCaptureRequest(CameraDevice cameraDevice,
+            Request request, HashMap<Surface, Integer> surfaceIdMap) throws CameraAccessException {
+        CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(request.templateId);
+        for (OutputConfigId configId : request.targetOutputConfigIds) {
+            boolean found = false;
+            for (Map.Entry<Surface, Integer> entry : surfaceIdMap.entrySet()) {
+                if (entry.getValue() == configId.id) {
+                    builder.addTarget(entry.getKey());
+                    found = true;
+                    break;
+                }
+            }
+
+            if (!found) {
+                Log.e(TAG, "Surface with output id: " + configId.id +
+                        " not found among registered camera outputs!");
+            }
+        }
+
+        builder.setTag(request.requestId);
+        CaptureRequest ret = builder.build();
+        CameraMetadataNative.update(ret.getNativeMetadata(), request.parameters);
+        return ret;
+    }
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index b578bf8..11b137ca 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -25,6 +25,7 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraExtensionCharacteristics;
 import android.hardware.camera2.CameraExtensionSession;
 import android.hardware.camera2.CameraOfflineSession;
 import android.hardware.camera2.CameraDevice;
@@ -138,6 +139,7 @@
 
     private CameraCaptureSessionCore mCurrentSession;
     private CameraExtensionSessionImpl mCurrentExtensionSession;
+    private CameraAdvancedExtensionSessionImpl mCurrentAdvancedExtensionSession;
     private int mNextSessionId = 0;
 
     private final int mAppTargetSdkVersion;
@@ -1343,6 +1345,12 @@
                 mCurrentExtensionSession.release();
                 mCurrentExtensionSession = null;
             }
+
+            if (mCurrentAdvancedExtensionSession != null) {
+                mCurrentAdvancedExtensionSession.release();
+                mCurrentAdvancedExtensionSession = null;
+            }
+
             // Only want to fire the onClosed callback once;
             // either a normal close where the remote device is valid
             // or a close after a startup error (no remote device but in error state)
@@ -2395,9 +2403,14 @@
     public void createExtensionSession(ExtensionSessionConfiguration extensionConfiguration)
             throws CameraAccessException {
         try {
-            mCurrentExtensionSession = CameraExtensionSessionImpl.createCameraExtensionSession(this,
-                    mContext,
-                    extensionConfiguration);
+            if (CameraExtensionCharacteristics.areAdvancedExtensionsSupported()) {
+                mCurrentAdvancedExtensionSession =
+                        CameraAdvancedExtensionSessionImpl.createCameraAdvancedExtensionSession(
+                                this, mContext, extensionConfiguration);
+            } else {
+                mCurrentExtensionSession = CameraExtensionSessionImpl.createCameraExtensionSession(
+                        this, mContext, extensionConfiguration);
+            }
         } catch (RemoteException e) {
             throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
         }
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
index 936734b..3b1cb94 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionJpegProcessor.java
@@ -16,6 +16,9 @@
 
 package android.hardware.camera2.impl;
 
+import static android.hardware.camera2.impl.CameraExtensionUtils.JPEG_DEFAULT_QUALITY;
+import static android.hardware.camera2.impl.CameraExtensionUtils.JPEG_DEFAULT_ROTATION;
+
 import android.annotation.NonNull;
 import android.graphics.ImageFormat;
 import android.hardware.camera2.CaptureResult;
@@ -42,8 +45,6 @@
 public class CameraExtensionJpegProcessor implements ICaptureProcessorImpl {
     public final static String TAG = "CameraExtensionJpeg";
     private final static int JPEG_QUEUE_SIZE = 1;
-    private final static int JPEG_DEFAULT_QUALITY = 100;
-    private final static int JPEG_DEFAULT_ROTATION = 0;
 
     private final Handler mHandler;
     private final HandlerThread mHandlerThread;
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 3d771c01..5339f41 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -110,79 +110,10 @@
     // Lock to synchronize cross-thread access to device public interface
     final Object mInterfaceLock = new Object(); // access from this class and Session only!
 
-    private static class SurfaceInfo {
-        public int mWidth = 0;
-        public int mHeight = 0;
-        public int mFormat = PixelFormat.RGBA_8888;
-        public long mUsage = 0;
-    }
-
-    private static final int SUPPORTED_CAPTURE_OUTPUT_FORMATS[] = {
-        CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
-        ImageFormat.JPEG
-    };
-
-    private static int nativeGetSurfaceWidth(Surface surface) {
-        return SurfaceUtils.getSurfaceSize(surface).getWidth();
-    }
-
-    private static int nativeGetSurfaceHeight(Surface surface) {
-        return SurfaceUtils.getSurfaceSize(surface).getHeight();
-    }
-
     private static int nativeGetSurfaceFormat(Surface surface) {
         return SurfaceUtils.getSurfaceFormat(surface);
     }
 
-    private static Surface getBurstCaptureSurface(
-            @NonNull List<OutputConfiguration> outputConfigs,
-            @NonNull HashMap<Integer, List<Size>> supportedCaptureSizes) {
-        for (OutputConfiguration config : outputConfigs) {
-            SurfaceInfo surfaceInfo = querySurface(config.getSurface());
-            for (int supportedFormat : SUPPORTED_CAPTURE_OUTPUT_FORMATS) {
-                if (surfaceInfo.mFormat == supportedFormat) {
-                    Size captureSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
-                    if (supportedCaptureSizes.containsKey(supportedFormat)) {
-                        if (supportedCaptureSizes.get(surfaceInfo.mFormat).contains(captureSize)) {
-                            return config.getSurface();
-                        } else {
-                            throw new IllegalArgumentException("Capture size not supported!");
-                        }
-                    }
-                    return config.getSurface();
-                }
-            }
-        }
-
-        return null;
-    }
-
-    private static @Nullable Surface getRepeatingRequestSurface(
-            @NonNull List<OutputConfiguration> outputConfigs,
-            @Nullable List<Size> supportedPreviewSizes) {
-        for (OutputConfiguration config : outputConfigs) {
-            SurfaceInfo surfaceInfo = querySurface(config.getSurface());
-            if ((surfaceInfo.mFormat ==
-                    CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT) ||
-                    // The default RGBA_8888 is also implicitly supported because camera will
-                    // internally override it to
-                    // 'CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT'
-                    (surfaceInfo.mFormat == PixelFormat.RGBA_8888)) {
-                Size repeatingRequestSurfaceSize = new Size(surfaceInfo.mWidth,
-                        surfaceInfo.mHeight);
-                if ((supportedPreviewSizes == null) ||
-                        (!supportedPreviewSizes.contains(repeatingRequestSurfaceSize))) {
-                    throw new IllegalArgumentException("Repeating request surface size " +
-                            repeatingRequestSurfaceSize + " not supported!");
-                }
-
-                return config.getSurface();
-            }
-        }
-
-        return null;
-    }
-
     /**
      * @hide
      */
@@ -221,22 +152,22 @@
         int suitableSurfaceCount = 0;
         List<Size> supportedPreviewSizes = extensionChars.getExtensionSupportedSizes(
                 config.getExtension(), SurfaceTexture.class);
-        Surface repeatingRequestSurface = getRepeatingRequestSurface(
+        Surface repeatingRequestSurface = CameraExtensionUtils.getRepeatingRequestSurface(
                 config.getOutputConfigurations(), supportedPreviewSizes);
         if (repeatingRequestSurface != null) {
             suitableSurfaceCount++;
         }
 
         HashMap<Integer, List<Size>> supportedCaptureSizes = new HashMap<>();
-        for (int format : SUPPORTED_CAPTURE_OUTPUT_FORMATS) {
+        for (int format : CameraExtensionUtils.SUPPORTED_CAPTURE_OUTPUT_FORMATS) {
             List<Size> supportedSizes = extensionChars.getExtensionSupportedSizes(
                     config.getExtension(), format);
             if (supportedSizes != null) {
                 supportedCaptureSizes.put(format, supportedSizes);
             }
         }
-        Surface burstCaptureSurface = getBurstCaptureSurface(config.getOutputConfigurations(),
-                supportedCaptureSizes);
+        Surface burstCaptureSurface = CameraExtensionUtils.getBurstCaptureSurface(
+                config.getOutputConfigurations(), supportedCaptureSizes);
         if (burstCaptureSurface != null) {
             suitableSurfaceCount++;
         }
@@ -266,15 +197,15 @@
         return session;
     }
 
-    private CameraExtensionSessionImpl(@NonNull IImageCaptureExtenderImpl imageExtender,
-                                       @NonNull IPreviewExtenderImpl previewExtender,
-                                       @NonNull List<Size> previewSizes,
-                                       long extensionClientId,
-                                       @NonNull CameraDevice cameraDevice,
-                                       @Nullable Surface repeatingRequestSurface,
-                                       @Nullable Surface burstCaptureSurface,
-                                       @NonNull StateCallback callback,
-                                       @NonNull Executor executor) {
+    public CameraExtensionSessionImpl(@NonNull IImageCaptureExtenderImpl imageExtender,
+            @NonNull IPreviewExtenderImpl previewExtender,
+            @NonNull List<Size> previewSizes,
+            long extensionClientId,
+            @NonNull CameraDevice cameraDevice,
+            @Nullable Surface repeatingRequestSurface,
+            @Nullable Surface burstCaptureSurface,
+            @NonNull StateCallback callback,
+            @NonNull Executor executor) {
         mExtensionClientId = extensionClientId;
         mImageExtender = imageExtender;
         mPreviewExtender = previewExtender;
@@ -290,57 +221,17 @@
         mInitialized = false;
     }
 
-    private static @NonNull SurfaceInfo querySurface(@NonNull Surface s) {
-        ImageWriter writer = null;
-        Image img = null;
-        SurfaceInfo surfaceInfo = new SurfaceInfo();
-        int nativeFormat = nativeGetSurfaceFormat(s);
-        int dataspace = SurfaceUtils.getSurfaceDataspace(s);
-        // Jpeg surfaces cannot be queried for their usage and other parameters
-        // in the usual way below. A buffer can only be de-queued after the
-        // producer overrides the surface dimensions to (width*height) x 1.
-        if ((nativeFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) &&
-                (dataspace == StreamConfigurationMap.HAL_DATASPACE_V0_JFIF)) {
-            surfaceInfo.mFormat = ImageFormat.JPEG;
-            surfaceInfo.mWidth = nativeGetSurfaceWidth(s);
-            surfaceInfo.mHeight = nativeGetSurfaceHeight(s);
-            return surfaceInfo;
-        }
-
-        HardwareBuffer buffer = null;
-        try {
-            writer = ImageWriter.newInstance(s, 1);
-            img = writer.dequeueInputImage();
-            buffer = img.getHardwareBuffer();
-            surfaceInfo.mFormat = buffer.getFormat();
-            surfaceInfo.mWidth = buffer.getWidth();
-            surfaceInfo.mHeight = buffer.getHeight();
-            surfaceInfo.mUsage = buffer.getUsage();
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to query surface, returning defaults!");
-        } finally {
-            if (buffer != null) {
-                buffer.close();
-            }
-            if (img != null) {
-                img.close();
-            }
-            if (writer != null) {
-                writer.close();
-            }
-        }
-
-        return surfaceInfo;
-    }
-
     private void initializeRepeatingRequestPipeline() throws RemoteException {
-        SurfaceInfo repeatingSurfaceInfo = new SurfaceInfo();
+        CameraExtensionUtils.SurfaceInfo repeatingSurfaceInfo =
+                new CameraExtensionUtils.SurfaceInfo();
         mPreviewProcessorType = mPreviewExtender.getProcessorType();
         if (mClientRepeatingRequestSurface != null) {
-            repeatingSurfaceInfo = querySurface(mClientRepeatingRequestSurface);
+            repeatingSurfaceInfo = CameraExtensionUtils.querySurface(
+                    mClientRepeatingRequestSurface);
         } else {
             // Make the intermediate surface behave as any regular 'SurfaceTexture'
-            SurfaceInfo captureSurfaceInfo = querySurface(mClientCaptureSurface);
+            CameraExtensionUtils.SurfaceInfo captureSurfaceInfo = CameraExtensionUtils.querySurface(
+                    mClientCaptureSurface);
             Size captureSize = new Size(captureSurfaceInfo.mWidth, captureSurfaceInfo.mHeight);
             Size previewSize = findSmallestAspectMatchedSize(mSupportedPreviewSizes, captureSize);
             repeatingSurfaceInfo.mWidth = previewSize.getWidth();
@@ -418,7 +309,8 @@
 
         if (mImageProcessor != null) {
             if (mClientCaptureSurface != null) {
-                SurfaceInfo surfaceInfo = querySurface(mClientCaptureSurface);
+                CameraExtensionUtils.SurfaceInfo surfaceInfo = CameraExtensionUtils.querySurface(
+                        mClientCaptureSurface);
                 if (surfaceInfo.mFormat == ImageFormat.JPEG) {
                     mImageJpegProcessor = new CameraExtensionJpegProcessor(mImageProcessor);
                     mImageProcessor = mImageJpegProcessor;
@@ -501,7 +393,7 @@
         SessionConfiguration sessionConfig = new SessionConfiguration(
                 SessionConfiguration.SESSION_REGULAR,
                 outputList,
-                new HandlerExecutor(mHandler),
+                new CameraExtensionUtils.HandlerExecutor(mHandler),
                 new SessionStateHandler());
 
         if (!sessionParamsList.isEmpty()) {
@@ -656,7 +548,8 @@
             throw new UnsupportedOperationException("Failed to create still capture burst request");
         }
 
-        return mCaptureSession.captureBurstRequests(burstRequest, new HandlerExecutor(mHandler),
+        return mCaptureSession.captureBurstRequests(burstRequest,
+                new CameraExtensionUtils.HandlerExecutor(mHandler),
                 new BurstRequestHandler(request, executor, listener, requestMap,
                         mBurstCaptureImageCallback));
     }
@@ -724,7 +617,7 @@
         CaptureRequest repeatingRequest = createRequest(mCameraDevice,
                 captureStageList, mCameraRepeatingSurface, CameraDevice.TEMPLATE_PREVIEW);
         return mCaptureSession.setSingleRepeatingRequest(repeatingRequest,
-                new HandlerExecutor(mHandler), requestHandler);
+                new CameraExtensionUtils.HandlerExecutor(mHandler), requestHandler);
     }
 
     /** @hide */
@@ -1705,23 +1598,6 @@
         return ret;
     }
 
-    private final class HandlerExecutor implements Executor {
-        private final Handler mHandler;
-
-        public HandlerExecutor(Handler handler) {
-            mHandler = handler;
-        }
-
-        @Override
-        public void execute(Runnable runCmd) {
-            try {
-                mHandler.post(runCmd);
-            } catch (RejectedExecutionException e) {
-                Log.w(TAG, "Handler thread unavailable, skipping message!");
-            }
-        }
-    }
-
     private static ParcelImage initializeParcelImage(Image img) {
         ParcelImage parcelImage = new ParcelImage();
         parcelImage.buffer = img.getHardwareBuffer();
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
new file mode 100644
index 0000000..950d716b
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.impl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.HardwareBuffer;
+import android.hardware.camera2.CameraExtensionCharacteristics;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.camera2.utils.SurfaceUtils;
+import android.media.Image;
+import android.media.ImageWriter;
+import android.os.Handler;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+public final class CameraExtensionUtils {
+    private static final String TAG = "CameraExtensionUtils";
+
+    public final static int JPEG_DEFAULT_QUALITY = 100;
+    public final static int JPEG_DEFAULT_ROTATION = 0;
+
+    public static final int[] SUPPORTED_CAPTURE_OUTPUT_FORMATS = {
+            CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
+            ImageFormat.JPEG
+    };
+
+    public static class SurfaceInfo {
+        public int mWidth = 0;
+        public int mHeight = 0;
+        public int mFormat = PixelFormat.RGBA_8888;
+        public long mUsage = 0;
+    }
+
+    public static final class HandlerExecutor implements Executor {
+        private final Handler mHandler;
+
+        public HandlerExecutor(Handler handler) {
+            mHandler = handler;
+        }
+
+        @Override
+        public void execute(Runnable runCmd) {
+            try {
+                mHandler.post(runCmd);
+            } catch (RejectedExecutionException e) {
+                Log.w(TAG, "Handler thread unavailable, skipping message!");
+            }
+        }
+    }
+
+    public static @NonNull SurfaceInfo querySurface(@NonNull Surface s) {
+        ImageWriter writer = null;
+        Image img = null;
+        SurfaceInfo surfaceInfo = new SurfaceInfo();
+        int nativeFormat = SurfaceUtils.getSurfaceFormat(s);
+        int dataspace = SurfaceUtils.getSurfaceDataspace(s);
+        // Jpeg surfaces cannot be queried for their usage and other parameters
+        // in the usual way below. A buffer can only be de-queued after the
+        // producer overrides the surface dimensions to (width*height) x 1.
+        if ((nativeFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) &&
+                (dataspace == StreamConfigurationMap.HAL_DATASPACE_V0_JFIF)) {
+            surfaceInfo.mFormat = ImageFormat.JPEG;
+            Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
+            surfaceInfo.mWidth = surfaceSize.getWidth();
+            surfaceInfo.mHeight = surfaceSize.getHeight();
+            return surfaceInfo;
+        }
+
+        HardwareBuffer buffer = null;
+        try {
+            writer = ImageWriter.newInstance(s, 1);
+            img = writer.dequeueInputImage();
+            buffer = img.getHardwareBuffer();
+            surfaceInfo.mFormat = buffer.getFormat();
+            surfaceInfo.mWidth = buffer.getWidth();
+            surfaceInfo.mHeight = buffer.getHeight();
+            surfaceInfo.mUsage = buffer.getUsage();
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to query surface, returning defaults!");
+        } finally {
+            if (buffer != null) {
+                buffer.close();
+            }
+            if (img != null) {
+                img.close();
+            }
+            if (writer != null) {
+                writer.close();
+            }
+        }
+
+        return surfaceInfo;
+    }
+
+    public static Surface getBurstCaptureSurface(
+            @NonNull List<OutputConfiguration> outputConfigs,
+            @NonNull HashMap<Integer, List<Size>> supportedCaptureSizes) {
+        for (OutputConfiguration config : outputConfigs) {
+            SurfaceInfo surfaceInfo = querySurface(config.getSurface());
+            for (int supportedFormat : SUPPORTED_CAPTURE_OUTPUT_FORMATS) {
+                if (surfaceInfo.mFormat == supportedFormat) {
+                    Size captureSize = new Size(surfaceInfo.mWidth, surfaceInfo.mHeight);
+                    if (supportedCaptureSizes.containsKey(supportedFormat)) {
+                        if (supportedCaptureSizes.get(surfaceInfo.mFormat).contains(captureSize)) {
+                            return config.getSurface();
+                        } else {
+                            throw new IllegalArgumentException("Capture size not supported!");
+                        }
+                    }
+                    return config.getSurface();
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public static @Nullable Surface getRepeatingRequestSurface(
+            @NonNull List<OutputConfiguration> outputConfigs,
+            @Nullable List<Size> supportedPreviewSizes) {
+        for (OutputConfiguration config : outputConfigs) {
+            SurfaceInfo surfaceInfo = querySurface(config.getSurface());
+            if ((surfaceInfo.mFormat ==
+                    CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT) ||
+                    // The default RGBA_8888 is also implicitly supported because camera will
+                    // internally override it to
+                    // 'CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT'
+                    (surfaceInfo.mFormat == PixelFormat.RGBA_8888)) {
+                Size repeatingRequestSurfaceSize = new Size(surfaceInfo.mWidth,
+                        surfaceInfo.mHeight);
+                if ((supportedPreviewSizes == null) ||
+                        (!supportedPreviewSizes.contains(repeatingRequestSurfaceSize))) {
+                    throw new IllegalArgumentException("Repeating request surface size " +
+                            repeatingRequestSurfaceSize + " not supported!");
+                }
+
+                return config.getSurface();
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 9a27a99..55c90ce 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -69,8 +69,6 @@
     private static final int MSG_SET_FEATURE_COMPLETED = 107;
     private static final int MSG_CHALLENGE_GENERATED = 108;
     private static final int MSG_FACE_DETECTED = 109;
-    private static final int MSG_CHALLENGE_INTERRUPTED = 110;
-    private static final int MSG_CHALLENGE_INTERRUPT_FINISHED = 111;
     private static final int MSG_AUTHENTICATION_FRAME = 112;
     private static final int MSG_ENROLLMENT_FRAME = 113;
 
@@ -102,8 +100,8 @@
 
         @Override // binder call
         public void onAuthenticationSucceeded(Face face, int userId, boolean isStrongBiometric) {
-            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId, isStrongBiometric ? 1 : 0,
-                    face).sendToTarget();
+            mHandler.obtainMessage(MSG_AUTHENTICATION_SUCCEEDED, userId,
+                    isStrongBiometric ? 1 : 0, face).sendToTarget();
         }
 
         @Override // binder call
@@ -142,22 +140,12 @@
         }
 
         @Override
-        public void onChallengeGenerated(int sensorId, long challenge) {
-            mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, sensorId, 0, challenge)
+        public void onChallengeGenerated(int sensorId, int userId, long challenge) {
+            mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, sensorId, userId, challenge)
                     .sendToTarget();
         }
 
         @Override
-        public void onChallengeInterrupted(int sensorId) {
-            mHandler.obtainMessage(MSG_CHALLENGE_INTERRUPTED, sensorId).sendToTarget();
-        }
-
-        @Override
-        public void onChallengeInterruptFinished(int sensorId) {
-            mHandler.obtainMessage(MSG_CHALLENGE_INTERRUPT_FINISHED, sensorId).sendToTarget();
-        }
-
-        @Override
         public void onAuthenticationFrame(FaceAuthenticationFrame frame) {
             mHandler.obtainMessage(MSG_AUTHENTICATION_FRAME, frame).sendToTarget();
         }
@@ -434,16 +422,14 @@
      *
      * @see com.android.server.locksettings.LockSettingsService
      *
-     * TODO(b/171335732): should take userId
-     *
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
-    public void generateChallenge(int sensorId, GenerateChallengeCallback callback) {
+    public void generateChallenge(int sensorId, int userId, GenerateChallengeCallback callback) {
         if (mService != null) {
             try {
                 mGenerateChallengeCallback = callback;
-                mService.generateChallenge(mToken, sensorId, 0 /* userId */, mServiceReceiver,
+                mService.generateChallenge(mToken, sensorId, userId, mServiceReceiver,
                         mContext.getOpPackageName());
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
@@ -452,12 +438,13 @@
     }
 
     /**
-     * Same as {@link #generateChallenge(int, GenerateChallengeCallback)}, but assumes the first
-     * enumerated sensor.
+     * Same as {@link #generateChallenge(int, int, GenerateChallengeCallback)}, but assumes the
+     * first enumerated sensor.
+     *
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
-    public void generateChallenge(GenerateChallengeCallback callback) {
+    public void generateChallenge(int userId, GenerateChallengeCallback callback) {
         final List<FaceSensorPropertiesInternal> faceSensorProperties =
                 getSensorPropertiesInternal();
         if (faceSensorProperties.isEmpty()) {
@@ -466,7 +453,7 @@
         }
 
         final int sensorId = faceSensorProperties.get(0).sensorId;
-        generateChallenge(sensorId, callback);
+        generateChallenge(sensorId, userId, callback);
     }
 
     /**
@@ -1120,25 +1107,16 @@
     }
 
     /**
-     * Callback structure provided to {@link #generateChallenge(int, GenerateChallengeCallback)}.
+     * Callback structure provided to {@link #generateChallenge(int, int,
+     * GenerateChallengeCallback)}.
+     *
      * @hide
      */
     public interface GenerateChallengeCallback {
         /**
          * Invoked when a challenge has been generated.
          */
-        void onGenerateChallengeResult(int sensorId, long challenge);
-
-        /**
-         * Invoked if the challenge has not been revoked and a subsequent caller/owner invokes
-         * {@link #generateChallenge(int, GenerateChallengeCallback)}, but
-         */
-        default void onChallengeInterrupted(int sensorId) {}
-
-        /**
-         * Invoked when the interrupting client has finished (e.g. revoked its challenge).
-         */
-        default void onChallengeInterruptFinished(int sensorId) {}
+        void onGenerateChallengeResult(int sensorId, int userId, long challenge);
     }
 
     private class OnEnrollCancelListener implements OnCancelListener {
@@ -1212,18 +1190,13 @@
                     args.recycle();
                     break;
                 case MSG_CHALLENGE_GENERATED:
-                    sendChallengeGenerated(msg.arg1 /* sensorId */, (long) msg.obj /* challenge */);
+                    sendChallengeGenerated(msg.arg1 /* sensorId */, msg.arg2 /* userId */,
+                            (long) msg.obj /* challenge */);
                     break;
                 case MSG_FACE_DETECTED:
                     sendFaceDetected(msg.arg1 /* sensorId */, msg.arg2 /* userId */,
                             (boolean) msg.obj /* isStrongBiometric */);
                     break;
-                case MSG_CHALLENGE_INTERRUPTED:
-                    sendChallengeInterrupted((int) msg.obj /* sensorId */);
-                    break;
-                case MSG_CHALLENGE_INTERRUPT_FINISHED:
-                    sendChallengeInterruptFinished((int) msg.obj /* sensorId */);
-                    break;
                 case MSG_AUTHENTICATION_FRAME:
                     sendAuthenticationFrame((FaceAuthenticationFrame) msg.obj /* frame */);
                     break;
@@ -1251,11 +1224,11 @@
         mGetFeatureCallback.onCompleted(success, features, featureState);
     }
 
-    private void sendChallengeGenerated(int sensorId, long challenge) {
+    private void sendChallengeGenerated(int sensorId, int userId, long challenge) {
         if (mGenerateChallengeCallback == null) {
             return;
         }
-        mGenerateChallengeCallback.onGenerateChallengeResult(sensorId, challenge);
+        mGenerateChallengeCallback.onGenerateChallengeResult(sensorId, userId, challenge);
     }
 
     private void sendFaceDetected(int sensorId, int userId, boolean isStrongBiometric) {
@@ -1266,22 +1239,6 @@
         mFaceDetectionCallback.onFaceDetected(sensorId, userId, isStrongBiometric);
     }
 
-    private void sendChallengeInterrupted(int sensorId) {
-        if (mGenerateChallengeCallback == null) {
-            Slog.e(TAG, "sendChallengeInterrupted, callback null");
-            return;
-        }
-        mGenerateChallengeCallback.onChallengeInterrupted(sensorId);
-    }
-
-    private void sendChallengeInterruptFinished(int sensorId) {
-        if (mGenerateChallengeCallback == null) {
-            Slog.e(TAG, "sendChallengeInterruptFinished, callback null");
-            return;
-        }
-        mGenerateChallengeCallback.onChallengeInterruptFinished(sensorId);
-    }
-
     private void sendRemovedResult(Face face, int remaining) {
         if (mRemovalCallback == null) {
             return;
diff --git a/core/java/android/hardware/face/FaceServiceReceiver.java b/core/java/android/hardware/face/FaceServiceReceiver.java
index 9e62ca5..9e78592 100644
--- a/core/java/android/hardware/face/FaceServiceReceiver.java
+++ b/core/java/android/hardware/face/FaceServiceReceiver.java
@@ -72,17 +72,8 @@
     }
 
     @Override
-    public void onChallengeGenerated(int sensorId, long challenge) throws RemoteException {
-
-    }
-
-    @Override
-    public void onChallengeInterrupted(int sensorId) throws RemoteException {
-
-    }
-
-    @Override
-    public void onChallengeInterruptFinished(int sensorId) throws RemoteException {
+    public void onChallengeGenerated(int sensorId, int userId, long challenge)
+            throws RemoteException {
 
     }
 
diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
index 0ccb395..c4d9bf2 100644
--- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl
+++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
@@ -33,9 +33,7 @@
     void onRemoved(in Face face, int remaining);
     void onFeatureSet(boolean success, int feature);
     void onFeatureGet(boolean success, in int[] features, in boolean[] featureState);
-    void onChallengeGenerated(int sensorId, long challenge);
-    void onChallengeInterrupted(int sensorId);
-    void onChallengeInterruptFinished(int sensorId);
+    void onChallengeGenerated(int sensorId, int userId, long challenge);
     void onAuthenticationFrame(in FaceAuthenticationFrame frame);
     void onEnrollmentFrame(in FaceEnrollFrame frame);
 }
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index b52955d..8aeb5cd 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -475,10 +475,13 @@
     }
 
     /**
+     * Callbacks for generate challenge operations.
+     *
      * @hide
      */
     public interface GenerateChallengeCallback {
-        void onChallengeGenerated(int sensorId, long challenge);
+        /** Called when a challenged has been generated. */
+        void onChallengeGenerated(int sensorId, int userId, long challenge);
     }
 
     /**
@@ -1124,7 +1127,8 @@
                     sendRemovedResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
                     break;
                 case MSG_CHALLENGE_GENERATED:
-                    sendChallengeGenerated(msg.arg1 /* sensorId */, (long) msg.obj /* challenge */);
+                    sendChallengeGenerated(msg.arg1 /* sensorId */, msg.arg2 /* userId */,
+                            (long) msg.obj /* challenge */);
                     break;
                 case MSG_FINGERPRINT_DETECTED:
                     sendFingerprintDetected(msg.arg1 /* sensorId */, msg.arg2 /* userId */,
@@ -1233,12 +1237,12 @@
         }
     }
 
-    private void sendChallengeGenerated(int sensorId, long challenge) {
+    private void sendChallengeGenerated(int sensorId, int userId, long challenge) {
         if (mGenerateChallengeCallback == null) {
             Slog.e(TAG, "sendChallengeGenerated, callback null");
             return;
         }
-        mGenerateChallengeCallback.onChallengeGenerated(sensorId, challenge);
+        mGenerateChallengeCallback.onChallengeGenerated(sensorId, userId, challenge);
     }
 
     private void sendFingerprintDetected(int sensorId, int userId, boolean isStrongBiometric) {
@@ -1454,8 +1458,8 @@
         }
 
         @Override // binder call
-        public void onChallengeGenerated(int sensorId, long challenge) {
-            mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, sensorId, 0, challenge)
+        public void onChallengeGenerated(int sensorId, int userId, long challenge) {
+            mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, sensorId, userId, challenge)
                     .sendToTarget();
         }
 
diff --git a/core/java/android/hardware/fingerprint/FingerprintServiceReceiver.java b/core/java/android/hardware/fingerprint/FingerprintServiceReceiver.java
index 798e87b..a9779b5 100644
--- a/core/java/android/hardware/fingerprint/FingerprintServiceReceiver.java
+++ b/core/java/android/hardware/fingerprint/FingerprintServiceReceiver.java
@@ -61,7 +61,8 @@
     }
 
     @Override
-    public void onChallengeGenerated(int sensorId, long challenge) throws RemoteException {
+    public void onChallengeGenerated(int sensorId, int userId, long challenge)
+            throws RemoteException {
 
     }
 
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index 1bd284d..9cea1fe 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -29,7 +29,7 @@
     void onAuthenticationFailed();
     void onError(int error, int vendorCode);
     void onRemoved(in Fingerprint fp, int remaining);
-    void onChallengeGenerated(int sensorId, long challenge);
+    void onChallengeGenerated(int sensorId, int userId, long challenge);
     void onUdfpsPointerDown(int sensorId);
     void onUdfpsPointerUp(int sensorId);
 }
diff --git a/core/java/android/hardware/fingerprint/IUdfpsHbmListener.aidl b/core/java/android/hardware/fingerprint/IUdfpsHbmListener.aidl
index 1551e07..f4d22da 100644
--- a/core/java/android/hardware/fingerprint/IUdfpsHbmListener.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsHbmListener.aidl
@@ -35,7 +35,7 @@
      * UdfpsController will call this method when the HBM is enabled.
      *
      * @param hbmType The type of HBM that was enabled. See
-     *        {@link com.android.systemui.biometrics.HbmTypes}.
+     *        {@link com.android.systemui.biometrics.UdfpsHbmTypes}.
      * @param displayId The displayId for which the HBM is enabled. See
      *        {@link android.view.Display#getDisplayId()}.
      */
@@ -45,7 +45,7 @@
      * UdfpsController will call this method when the HBM is disabled.
      *
      * @param hbmType The type of HBM that was disabled. See
-     *        {@link com.android.systemui.biometrics.HbmTypes}.
+     *        {@link com.android.systemui.biometrics.UdfpsHbmTypes}.
      * @param displayId The displayId for which the HBM is disabled. See
      *        {@link android.view.Display#getDisplayId()}.
      */
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index d7b96df..f0d410f 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1329,6 +1329,7 @@
                 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
         mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
         mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM);
+        mWindow.getWindow().getAttributes().receiveInsetsIgnoringZOrder = true;
 
         // Automotive devices may request the navigation bar to be hidden when the IME shows up
         // (controlled via config_automotiveHideNavBarForKeyboard) in order to maximize the visible
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 98acd98..01d1aa5 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -79,6 +79,16 @@
     public static final int DIRECTION_OUT = 1;
 
     /**
+     * Used when applying a transform to direct traffic through an {@link IpSecTransform} for
+     * forwarding between interfaces.
+     *
+     * <p>See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}.
+     *
+     * @hide
+     */
+    public static final int DIRECTION_FWD = 2;
+
+    /**
      * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
      *
      * <p>No IPsec packet may contain an SPI of 0.
diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java
index 9df861a..3915634 100644
--- a/core/java/android/net/NetworkStateSnapshot.java
+++ b/core/java/android/net/NetworkStateSnapshot.java
@@ -104,7 +104,10 @@
         return mSubscriberId;
     }
 
-    /** Get the legacy type of the network associated with this snapshot. */
+    /**
+     * Get the legacy type of the network associated with this snapshot.
+     * @return the legacy network type. See {@code ConnectivityManager#TYPE_*}.
+     */
     public int getLegacyType() {
         return mLegacyType;
     }
diff --git a/core/java/android/net/vcn/VcnNetworkPolicyResult.java b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
index 5e93820..14e70cf 100644
--- a/core/java/android/net/vcn/VcnNetworkPolicyResult.java
+++ b/core/java/android/net/vcn/VcnNetworkPolicyResult.java
@@ -87,6 +87,16 @@
                 && mNetworkCapabilities.equals(that.mNetworkCapabilities);
     }
 
+    @Override
+    public String toString() {
+        return "VcnNetworkPolicyResult { "
+                + "mIsTeardownRequested = "
+                + mIsTearDownRequested
+                + ", mNetworkCapabilities"
+                + mNetworkCapabilities
+                + " }";
+    }
+
     /** {@inheritDoc} */
     @Override
     public int describeContents() {
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
index b47d564..b0d4f3b 100644
--- a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java
@@ -85,6 +85,11 @@
         return mVcnNetworkPolicyResult.equals(that.mVcnNetworkPolicyResult);
     }
 
+    @Override
+    public String toString() {
+        return mVcnNetworkPolicyResult.toString();
+    }
+
     /** {@inheritDoc} */
     @Override
     public int describeContents() {
diff --git a/core/java/android/os/AggregateBatteryConsumer.java b/core/java/android/os/AggregateBatteryConsumer.java
index 449e3ae..ee86265 100644
--- a/core/java/android/os/AggregateBatteryConsumer.java
+++ b/core/java/android/os/AggregateBatteryConsumer.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 
+import java.io.PrintWriter;
+
 /**
  * Contains power consumption data across the entire device.
  *
@@ -38,6 +40,11 @@
     }
 
     @Override
+    public void dump(PrintWriter pw, boolean skipEmptyComponents) {
+        mPowerComponents.dump(pw, skipEmptyComponents);
+    }
+
+    @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
         dest.writeDouble(mConsumedPowerMah);
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index 6b628b0..edb30b0 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -27,7 +28,7 @@
  *
  * @hide
  */
-public class BatteryConsumer {
+public abstract class BatteryConsumer {
 
     /**
      * Power usage component, describing the particular part of the system
@@ -85,12 +86,37 @@
     public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
     public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
 
+    private static final String[] sPowerComponentNames = new String[POWER_COMPONENT_COUNT];
+
+    static {
+        // Assign individually to avoid future mismatch
+        sPowerComponentNames[POWER_COMPONENT_SCREEN] = "screen";
+        sPowerComponentNames[POWER_COMPONENT_CPU] = "cpu";
+        sPowerComponentNames[POWER_COMPONENT_BLUETOOTH] = "bluetooth";
+        sPowerComponentNames[POWER_COMPONENT_CAMERA] = "camera";
+        sPowerComponentNames[POWER_COMPONENT_AUDIO] = "audio";
+        sPowerComponentNames[POWER_COMPONENT_VIDEO] = "video";
+        sPowerComponentNames[POWER_COMPONENT_FLASHLIGHT] = "flashlight";
+        sPowerComponentNames[POWER_COMPONENT_SYSTEM_SERVICES] = "system_services";
+        sPowerComponentNames[POWER_COMPONENT_MOBILE_RADIO] = "mobile_radio";
+        sPowerComponentNames[POWER_COMPONENT_SENSORS] = "sensors";
+        sPowerComponentNames[POWER_COMPONENT_GNSS] = "gnss";
+        sPowerComponentNames[POWER_COMPONENT_WIFI] = "wifi";
+        sPowerComponentNames[POWER_COMPONENT_WAKELOCK] = "wakelock";
+        sPowerComponentNames[POWER_COMPONENT_MEMORY] = "memory";
+        sPowerComponentNames[POWER_COMPONENT_PHONE] = "phone";
+        sPowerComponentNames[POWER_COMPONENT_AMBIENT_DISPLAY] = "ambient_display";
+        sPowerComponentNames[POWER_COMPONENT_IDLE] = "idle";
+        sPowerComponentNames[POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS] = "reattributed";
+    }
+
     /**
      * Identifiers of models used for power estimation.
      *
      * @hide
      */
     @IntDef(prefix = {"POWER_MODEL_"}, value = {
+            POWER_MODEL_UNDEFINED,
             POWER_MODEL_POWER_PROFILE,
             POWER_MODEL_MEASURED_ENERGY,
     })
@@ -99,15 +125,20 @@
     }
 
     /**
+     * Unspecified power model.
+     */
+    public static final int POWER_MODEL_UNDEFINED = 0;
+
+    /**
      * Power model that is based on average consumption rates that hardware components
      * consume in various states.
      */
-    public static final int POWER_MODEL_POWER_PROFILE = 0;
+    public static final int POWER_MODEL_POWER_PROFILE = 1;
 
     /**
      * Power model that is based on energy consumption measured by on-device power monitors.
      */
-    public static final int POWER_MODEL_MEASURED_ENERGY = 1;
+    public static final int POWER_MODEL_MEASURED_ENERGY = 2;
 
     protected final PowerComponents mPowerComponents;
 
@@ -197,6 +228,41 @@
         mPowerComponents.writeToParcel(dest, flags);
     }
 
+    /**
+     * Returns the name of the specified component.  Intended for logging and debugging.
+     */
+    public static String powerComponentIdToString(@BatteryConsumer.PowerComponent int componentId) {
+        return sPowerComponentNames[componentId];
+    }
+
+    /**
+     * Returns the name of the specified power model.  Intended for logging and debugging.
+     */
+    public static String powerModelToString(@BatteryConsumer.PowerModel int powerModel) {
+        switch (powerModel) {
+            case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
+                return "measured energy";
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+                return "power profile";
+            default:
+                return "";
+        }
+    }
+
+    /**
+     * Prints the stats in a human-readable format.
+     */
+    public void dump(PrintWriter pw) {
+        dump(pw, true);
+    }
+
+    /**
+     * Prints the stats in a human-readable format.
+     *
+     * @param skipEmptyComponents if true, omit any power components with a zero amount.
+     */
+    public abstract void dump(PrintWriter pw, boolean skipEmptyComponents);
+
     protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
         final PowerComponents.Builder mPowerComponentsBuilder;
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index eec6810..4c8297a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -51,6 +51,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
+import com.android.internal.os.BatteryUsageStatsProvider;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -3930,7 +3931,6 @@
                 getStartClockTime(),
                 whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000,
                 getEstimatedBatteryCapacity(),
-                getLearnedBatteryCapacity(),
                 getMinLearnedBatteryCapacity(),
                 getMaxLearnedBatteryCapacity(),
                 screenDozeTime / 1000);
@@ -5299,154 +5299,19 @@
         pw.println(getDischargeAmountScreenDozeSinceCharge());
         pw.println();
 
+        final BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(context, this);
+        final BatteryUsageStats stats = provider.getBatteryUsageStats(
+                new BatteryUsageStatsQuery.Builder()
+                        .setMaxStatsAgeMs(0)
+                        .includePowerModels()
+                        .build());
+        stats.dump(pw, prefix);
+
         final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
         helper.create(this);
         helper.refreshStats(which, UserHandle.USER_ALL);
-        List<BatterySipper> sippers = helper.getUsageList();
-        if (sippers != null && sippers.size() > 0) {
-            pw.print(prefix); pw.println("  Estimated power use (mAh):");
-            pw.print(prefix); pw.print("    Capacity: ");
-                    printmAh(pw, helper.getPowerProfile().getBatteryCapacity());
-                    pw.print(", Computed drain: "); printmAh(pw, helper.getComputedPower());
-                    pw.print(", actual drain: "); printmAh(pw, helper.getMinDrainedPower());
-                    if (helper.getMinDrainedPower() != helper.getMaxDrainedPower()) {
-                        pw.print("-"); printmAh(pw, helper.getMaxDrainedPower());
-                    }
-                    pw.println();
-            for (int i=0; i<sippers.size(); i++) {
-                final BatterySipper bs = sippers.get(i);
-                pw.print(prefix);
-                switch (bs.drainType) {
-                    case AMBIENT_DISPLAY:
-                        pw.print("    Ambient display: ");
-                        break;
-                    case IDLE:
-                        pw.print("    Idle: ");
-                        break;
-                    case CELL:
-                        pw.print("    Cell standby: ");
-                        break;
-                    case PHONE:
-                        pw.print("    Phone calls: ");
-                        break;
-                    case WIFI:
-                        pw.print("    Wifi: ");
-                        break;
-                    case BLUETOOTH:
-                        pw.print("    Bluetooth: ");
-                        break;
-                    case SCREEN:
-                        pw.print("    Screen: ");
-                        break;
-                    case FLASHLIGHT:
-                        pw.print("    Flashlight: ");
-                        break;
-                    case APP:
-                        pw.print("    Uid ");
-                        UserHandle.formatUid(pw, bs.uidObj.getUid());
-                        pw.print(": ");
-                        break;
-                    case USER:
-                        pw.print("    User "); pw.print(bs.userId);
-                        pw.print(": ");
-                        break;
-                    case UNACCOUNTED:
-                        pw.print("    Unaccounted: ");
-                        break;
-                    case OVERCOUNTED:
-                        pw.print("    Over-counted: ");
-                        break;
-                    case CAMERA:
-                        pw.print("    Camera: ");
-                        break;
-                    default:
-                        pw.print("    ???: ");
-                        break;
-                }
-                printmAh(pw, bs.totalPowerMah);
 
-                if (bs.usagePowerMah != bs.totalPowerMah) {
-                    // If the usage (generic power) isn't the whole amount, we list out
-                    // what components are involved in the calculation.
-
-                    pw.print(" (");
-                    if (bs.usagePowerMah != 0) {
-                        pw.print(" usage=");
-                        printmAh(pw, bs.usagePowerMah);
-                    }
-                    if (bs.cpuPowerMah != 0) {
-                        pw.print(" cpu=");
-                        printmAh(pw, bs.cpuPowerMah);
-                    }
-                    if (bs.wakeLockPowerMah != 0) {
-                        pw.print(" wake=");
-                        printmAh(pw, bs.wakeLockPowerMah);
-                    }
-                    if (bs.mobileRadioPowerMah != 0) {
-                        pw.print(" radio=");
-                        printmAh(pw, bs.mobileRadioPowerMah);
-                    }
-                    if (bs.wifiPowerMah != 0) {
-                        pw.print(" wifi=");
-                        printmAh(pw, bs.wifiPowerMah);
-                    }
-                    if (bs.bluetoothPowerMah != 0) {
-                        pw.print(" bt=");
-                        printmAh(pw, bs.bluetoothPowerMah);
-                    }
-                    if (bs.gpsPowerMah != 0) {
-                        pw.print(" gps=");
-                        printmAh(pw, bs.gpsPowerMah);
-                    }
-                    if (bs.sensorPowerMah != 0) {
-                        pw.print(" sensor=");
-                        printmAh(pw, bs.sensorPowerMah);
-                    }
-                    if (bs.cameraPowerMah != 0) {
-                        pw.print(" camera=");
-                        printmAh(pw, bs.cameraPowerMah);
-                    }
-                    if (bs.flashlightPowerMah != 0) {
-                        pw.print(" flash=");
-                        printmAh(pw, bs.flashlightPowerMah);
-                    }
-                    if (bs.customMeasuredPowerMah != null) {
-                        for (int idx = 0; idx < bs.customMeasuredPowerMah.length; idx++) {
-                            final double customPowerMah = bs.customMeasuredPowerMah[idx];
-                            if (customPowerMah != 0) {
-                                pw.print(" custom[" + idx + "]=");
-                                printmAh(pw, customPowerMah);
-                            }
-                        }
-                    }
-                    pw.print(" )");
-                }
-
-                // If there is additional smearing information, include it.
-                if (bs.totalSmearedPowerMah != bs.totalPowerMah) {
-                    pw.print(" Including smearing: ");
-                    printmAh(pw, bs.totalSmearedPowerMah);
-                    pw.print(" (");
-                    if (bs.screenPowerMah != 0) {
-                        pw.print(" screen=");
-                        printmAh(pw, bs.screenPowerMah);
-                    }
-                    if (bs.proportionalSmearMah != 0) {
-                        pw.print(" proportional=");
-                        printmAh(pw, bs.proportionalSmearMah);
-                    }
-                    pw.print(" )");
-                }
-                if (bs.shouldHide) {
-                    pw.print(" Excluded from smearing");
-                }
-
-                pw.println();
-            }
-            pw.println();
-        }
-
-        sippers = helper.getMobilemsppList();
+        final List<BatterySipper> sippers = helper.getMobilemsppList();
         if (sippers != null && sippers.size() > 0) {
             pw.print(prefix); pw.println("  Per-app mobile ms per packet:");
             long totalTime = 0;
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 6bc861f..3225667 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -23,10 +23,13 @@
 
 import com.android.internal.os.BatteryStatsHistory;
 import com.android.internal.os.BatteryStatsHistoryIterator;
+import com.android.internal.os.PowerCalculator;
 
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
 
 /**
@@ -73,6 +76,7 @@
 
     private final int mDischargePercentage;
     private final long mStatsStartTimestampMs;
+    private final double mBatteryCapacityMah;
     private final double mDischargedPowerLowerBound;
     private final double mDischargedPowerUpperBound;
     private final long mBatteryTimeRemainingMs;
@@ -86,6 +90,7 @@
 
     private BatteryUsageStats(@NonNull Builder builder) {
         mStatsStartTimestampMs = builder.mStatsStartTimestampMs;
+        mBatteryCapacityMah = builder.mBatteryCapacityMah;
         mDischargePercentage = builder.mDischargePercentage;
         mDischargedPowerLowerBound = builder.mDischargedPowerLowerBoundMah;
         mDischargedPowerUpperBound = builder.mDischargedPowerUpperBoundMah;
@@ -145,6 +150,13 @@
     }
 
     /**
+     * Returns battery capacity in milli-amp-hours.
+     */
+    public double getBatteryCapacity() {
+        return mBatteryCapacityMah;
+    }
+
+    /**
      * Portion of battery charge drained since BatteryStats reset (e.g. due to being fully
      * charged), as percentage of the full charge in the range [0:100]
      */
@@ -217,6 +229,7 @@
 
     private BatteryUsageStats(@NonNull Parcel source) {
         mStatsStartTimestampMs = source.readLong();
+        mBatteryCapacityMah = source.readDouble();
         mDischargePercentage = source.readInt();
         mDischargedPowerLowerBound = source.readDouble();
         mDischargedPowerUpperBound = source.readDouble();
@@ -274,6 +287,7 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeLong(mStatsStartTimestampMs);
+        dest.writeDouble(mBatteryCapacityMah);
         dest.writeInt(mDischargePercentage);
         dest.writeDouble(mDischargedPowerLowerBound);
         dest.writeDouble(mDischargedPowerUpperBound);
@@ -322,6 +336,104 @@
     };
 
     /**
+     * Prints the stats in a human-readable format.
+     */
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix);
+        pw.println("  Estimated power use (mAh):");
+        pw.print(prefix);
+        pw.print("    Capacity: ");
+        PowerCalculator.printPowerMah(pw, getBatteryCapacity());
+        pw.print(", Computed drain: ");
+        PowerCalculator.printPowerMah(pw, getConsumedPower());
+        final Range<Double> dischargedPowerRange = getDischargedPowerRange();
+        pw.print(", actual drain: ");
+        PowerCalculator.printPowerMah(pw, dischargedPowerRange.getLower());
+        if (!dischargedPowerRange.getLower().equals(dischargedPowerRange.getUpper())) {
+            pw.print("-");
+            PowerCalculator.printPowerMah(pw, dischargedPowerRange.getUpper());
+        }
+        pw.println();
+
+        pw.println("    Global");
+        final BatteryConsumer deviceConsumer = getAggregateBatteryConsumer(
+                AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
+        final BatteryConsumer appsConsumer = getAggregateBatteryConsumer(
+                AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS);
+
+        for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
+                componentId++) {
+            final double devicePowerMah = deviceConsumer.getConsumedPower(componentId);
+            final double appsPowerMah = appsConsumer.getConsumedPower(componentId);
+            if (devicePowerMah == 0 && appsPowerMah == 0) {
+                continue;
+            }
+
+            final String componentName = BatteryConsumer.powerComponentIdToString(componentId);
+            printPowerComponent(pw, prefix, componentName, devicePowerMah, appsPowerMah,
+                    deviceConsumer.getPowerModel(componentId),
+                    deviceConsumer.getUsageDurationMillis(componentId));
+        }
+
+        for (int componentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
+                componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
+                        + mCustomPowerComponentNames.length;
+                componentId++) {
+            final double devicePowerMah =
+                    deviceConsumer.getConsumedPowerForCustomComponent(componentId);
+            final double appsPowerMah =
+                    appsConsumer.getConsumedPowerForCustomComponent(componentId);
+            if (devicePowerMah == 0 && appsPowerMah == 0) {
+                continue;
+            }
+
+            printPowerComponent(pw, prefix, deviceConsumer.getCustomPowerComponentName(componentId),
+                    devicePowerMah, appsPowerMah,
+                    BatteryConsumer.POWER_MODEL_UNDEFINED,
+                    deviceConsumer.getUsageDurationForCustomComponentMillis(componentId));
+        }
+
+        dumpSortedBatteryConsumers(pw, prefix, getUidBatteryConsumers());
+        dumpSortedBatteryConsumers(pw, prefix, getUserBatteryConsumers());
+    }
+
+    private void printPowerComponent(PrintWriter pw, String prefix, String componentName,
+            double devicePowerMah, double appsPowerMah, int powerModel, long durationMs) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(prefix).append("      ").append(componentName).append(": ")
+                .append(PowerCalculator.formatCharge(devicePowerMah));
+        if (powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED
+                && powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+            sb.append(" [");
+            sb.append(BatteryConsumer.powerModelToString(powerModel));
+            sb.append("]");
+        }
+        sb.append(" apps: ").append(PowerCalculator.formatCharge(appsPowerMah));
+        if (durationMs != 0) {
+            sb.append(" duration: ");
+            BatteryStats.formatTimeMs(sb, durationMs);
+        }
+
+        pw.println(sb.toString());
+    }
+
+    private void dumpSortedBatteryConsumers(PrintWriter pw, String prefix,
+            List<? extends BatteryConsumer> batteryConsumers) {
+        batteryConsumers.sort(
+                Comparator.<BatteryConsumer>comparingDouble(BatteryConsumer::getConsumedPower)
+                        .reversed());
+        for (BatteryConsumer consumer : batteryConsumers) {
+            if (consumer.getConsumedPower() == 0) {
+                continue;
+            }
+            pw.print(prefix);
+            pw.print("    ");
+            consumer.dump(pw);
+            pw.println();
+        }
+    }
+
+    /**
      * Builder for BatteryUsageStats.
      */
     public static final class Builder {
@@ -329,6 +441,7 @@
         private final String[] mCustomPowerComponentNames;
         private final boolean mIncludePowerModels;
         private long mStatsStartTimestampMs;
+        private double mBatteryCapacityMah;
         private int mDischargePercentage;
         private double mDischargedPowerLowerBoundMah;
         private double mDischargedPowerUpperBoundMah;
@@ -365,6 +478,14 @@
         }
 
         /**
+         * Sets the battery capacity in milli-amp-hours.
+         */
+        public Builder setBatteryCapacity(double batteryCapacityMah) {
+            mBatteryCapacityMah = batteryCapacityMah;
+            return this;
+        }
+
+        /**
          * Sets the timestamp of the latest battery stats reset, in milliseconds.
          */
         public Builder setStatsStartTimestamp(long statsStartTimestampMs) {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 5b3bc26..900659b 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -309,7 +309,7 @@
          * booted, but it may increase when the hardware manufacturer provides an OTA update.
          * <p>
          * Possible non-zero values are defined in {@link Build.VERSION_CODES} starting with
-         * {@link Build.VERSION_CODES#S}.
+         * {@link Build.VERSION_CODES#R}.
          */
         public static final int MEDIA_PERFORMANCE_CLASS =
                 DeviceProperties.media_performance_class().orElse(0);
@@ -437,7 +437,8 @@
          * Magic version number for a current development build, which has
          * not yet turned into an official release.
          */
-        public static final int CUR_DEVELOPMENT = VMRuntime.SDK_VERSION_CUR_DEVELOPMENT;
+        // This must match VMRuntime.SDK_VERSION_CUR_DEVELOPMENT.
+        public static final int CUR_DEVELOPMENT = 10000;
 
         /**
          * October 2008: The original, first, version of Android.  Yay!
@@ -1324,6 +1325,7 @@
      * selinux into "permissive" mode in particular.
      * @hide
      */
+    @UnsupportedAppUsage
     public static final boolean IS_DEBUGGABLE =
             SystemProperties.getInt("ro.debuggable", 0) == 1;
 
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index b8bb353..d90e129 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -74,8 +74,9 @@
      *
      * @deprecated Accurate counting is a burden on the runtime and may be removed.
      */
+    // This must match VMDebug.TRACE_COUNT_ALLOCS.
     @Deprecated
-    public static final int TRACE_COUNT_ALLOCS  = VMDebug.TRACE_COUNT_ALLOCS;
+    public static final int TRACE_COUNT_ALLOCS  = 1;
 
     /**
      * Flags for printLoadedClasses().  Default behavior is to only show
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 47a2edc..964f1b6 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -17,6 +17,10 @@
 
 import android.annotation.NonNull;
 
+import com.android.internal.os.PowerCalculator;
+
+import java.io.PrintWriter;
+
 /**
  * Contains details of battery attribution data broken down to individual power drain types
  * such as CPU, RAM, GPU etc.
@@ -202,6 +206,37 @@
         return max;
     }
 
+    public void dump(PrintWriter pw, boolean skipEmptyComponents) {
+        String separator = "";
+        for (int componentId = 0; componentId < BatteryConsumer.POWER_COMPONENT_COUNT;
+                componentId++) {
+            final double componentPower = getConsumedPower(componentId);
+            if (skipEmptyComponents && componentPower == 0) {
+                continue;
+            }
+            pw.print(separator); separator = " ";
+            pw.print(BatteryConsumer.powerComponentIdToString(componentId));
+            pw.print("=");
+            PowerCalculator.printPowerMah(pw, componentPower);
+        }
+
+        final int customComponentCount = getCustomPowerComponentCount();
+        for (int customComponentId = BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
+                customComponentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
+                        + customComponentCount;
+                customComponentId++) {
+            final double customComponentPower =
+                    getConsumedPowerForCustomComponent(customComponentId);
+            if (skipEmptyComponents && customComponentPower == 0) {
+                continue;
+            }
+            pw.print(separator); separator = " ";
+            pw.print(getCustomPowerComponentName(customComponentId));
+            pw.print("=");
+            PowerCalculator.printPowerMah(pw, customComponentPower);
+        }
+    }
+
     /**
      * Builder for PowerComponents.
      */
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index f9e4f73..6bca336 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -250,6 +250,12 @@
     public static final int EXT_OBB_RW_GID = 1079;
 
     /**
+     * Defines the UID/GID for the Uwb service process.
+     * @hide
+     */
+    public static final int UWB_UID = 1083;
+
+    /**
      * GID that corresponds to the INTERNET permission.
      * Must match the value of AID_INET.
      * @hide
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index b1fb570..16a6c76 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -20,6 +20,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import com.android.internal.os.PowerCalculator;
+
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -112,6 +115,18 @@
         dest.writeLong(mTimeInBackgroundMs);
     }
 
+    @Override
+    public void dump(PrintWriter pw, boolean skipEmptyComponents) {
+        final double consumedPower = getConsumedPower();
+        pw.print("UID ");
+        UserHandle.formatUid(pw, getUid());
+        pw.print(": ");
+        PowerCalculator.printPowerMah(pw, consumedPower);
+        pw.print(" ( ");
+        mPowerComponents.dump(pw, skipEmptyComponents  /* skipTotalPowerComponent */);
+        pw.print(" ) ");
+    }
+
     @NonNull
     public static final Creator<UidBatteryConsumer> CREATOR = new Creator<UidBatteryConsumer>() {
         public UidBatteryConsumer createFromParcel(@NonNull Parcel source) {
diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java
index d0d0d38..429d2c5 100644
--- a/core/java/android/os/UserBatteryConsumer.java
+++ b/core/java/android/os/UserBatteryConsumer.java
@@ -18,6 +18,9 @@
 
 import android.annotation.NonNull;
 
+import com.android.internal.os.PowerCalculator;
+
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -52,6 +55,18 @@
         dest.writeInt(mUserId);
     }
 
+    @Override
+    public void dump(PrintWriter pw, boolean skipEmptyComponents) {
+        final double consumedPower = getConsumedPower();
+        pw.print("User ");
+        pw.print(mUserId);
+        pw.print(": ");
+        PowerCalculator.printPowerMah(pw, consumedPower);
+        pw.print(" ( ");
+        mPowerComponents.dump(pw, skipEmptyComponents  /* skipTotalPowerComponent */);
+        pw.print(" ) ");
+    }
+
     public static final Creator<UserBatteryConsumer> CREATOR =
             new Creator<UserBatteryConsumer>() {
                 @Override
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c51c506..b879082 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8545,9 +8545,10 @@
                 "one_handed_tutorial_show_count";
 
         /**
-         * Indicates whether ui translation is enabled.
+         * Toggle to enable/disable for the apps to use the Ui translation for Views. The value
+         * indicates whether the Ui translation is enabled by the user.
          * <p>
-         * Type: int (0 for false, 1 for true)
+         * Type: {@code int} ({@code 0} for disabled, {@code 1} for enabled)
          *
          * @hide
          */
@@ -9920,6 +9921,18 @@
                 "accessibility_floating_menu_opacity";
 
         /**
+         * Prompts the user to the Accessibility button is replaced with the floating menu.
+         * <ul>
+         *    <li> 0 = disabled </li>
+         *    <li> 1 = enabled </li>
+         * </ul>
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT =
+                "accessibility_floating_menu_migration_tooltip_prompt";
+
+        /**
          * Whether the Adaptive connectivity option is enabled.
          *
          * @hide
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index 5f41174..473e7ae 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -16,9 +16,6 @@
 
 package android.service.voice;
 
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-
-import android.annotation.CallSuper;
 import android.annotation.DurationMillisLong;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -33,10 +30,8 @@
 import android.hardware.soundtrigger.SoundTrigger;
 import android.media.AudioFormat;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
-import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
@@ -67,6 +62,8 @@
  * to inform the system that a keyphrase was not detected. The system then relays this result to
  * the {@link VoiceInteractionService} through {@link HotwordDetector.Callback}.
  *
+ * Note: Methods in this class may be called concurrently
+ *
  * @hide
  */
 @SystemApi
@@ -138,8 +135,6 @@
     public static final String SERVICE_INTERFACE =
             "android.service.voice.HotwordDetectionService";
 
-    private Handler mHandler;
-
     @Nullable
     private ContentCaptureManager mContentCaptureManager;
 
@@ -154,13 +149,12 @@
             if (DBG) {
                 Log.d(TAG, "#detectFromDspSource");
             }
-            mHandler.sendMessage(obtainMessage(HotwordDetectionService::onDetect,
-                    HotwordDetectionService.this,
+            HotwordDetectionService.this.onDetect(
                     new AlwaysOnHotwordDetector.EventPayload(
                             event.triggerInData, event.captureAvailable,
                             event.captureFormat, event.captureSession, event.data),
                     timeoutMillis,
-                    new Callback(callback)));
+                    new Callback(callback));
         }
 
         @Override
@@ -169,11 +163,10 @@
             if (DBG) {
                 Log.d(TAG, "#updateState");
             }
-            mHandler.sendMessage(obtainMessage(HotwordDetectionService::onUpdateStateInternal,
-                    HotwordDetectionService.this,
+            HotwordDetectionService.this.onUpdateStateInternal(
                     options,
                     sharedMemory,
-                    callback));
+                    callback);
         }
 
         @Override
@@ -189,19 +182,15 @@
             }
             switch (audioSource) {
                 case AUDIO_SOURCE_MICROPHONE:
-                    mHandler.sendMessage(obtainMessage(
-                            HotwordDetectionService::onDetect,
-                            HotwordDetectionService.this,
-                            new Callback(callback)));
+                    HotwordDetectionService.this.onDetect(
+                            new Callback(callback));
                     break;
                 case AUDIO_SOURCE_EXTERNAL:
-                    mHandler.sendMessage(obtainMessage(
-                            HotwordDetectionService::onDetect,
-                            HotwordDetectionService.this,
+                    HotwordDetectionService.this.onDetect(
                             audioStream,
                             audioFormat,
                             options,
-                            new Callback(callback)));
+                            new Callback(callback));
                     break;
                 default:
                     Log.i(TAG, "Unsupported audio source " + audioSource);
@@ -216,13 +205,6 @@
         }
     };
 
-    @CallSuper
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mHandler = Handler.createAsync(Looper.getMainLooper());
-    }
-
     @Override
     @Nullable
     public final IBinder onBind(@NonNull Intent intent) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 53bde36..324d1ab 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -21,6 +21,7 @@
 import static android.graphics.Matrix.MSKEW_X;
 import static android.graphics.Matrix.MSKEW_Y;
 import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import android.annotation.FloatRange;
 import android.annotation.NonNull;
@@ -1218,7 +1219,9 @@
             mIWallpaperEngine.mDisplayManager.registerDisplayListener(mDisplayListener,
                     mCaller.getHandler());
             mDisplay = mIWallpaperEngine.mDisplay;
-            mDisplayContext = createDisplayContext(mDisplay);
+            // Use window context of TYPE_WALLPAPER so client can access UI resources correctly.
+            mDisplayContext = createDisplayContext(mDisplay)
+                    .createWindowContext(TYPE_WALLPAPER, null /* options */);
             mDisplayState = mDisplay.getState();
 
             if (DEBUG) Log.v(TAG, "onCreate(): " + this);
diff --git a/core/java/android/text/method/TranslationTransformationMethod.java b/core/java/android/text/method/TranslationTransformationMethod.java
index 54c0ffc..80387aa 100644
--- a/core/java/android/text/method/TranslationTransformationMethod.java
+++ b/core/java/android/text/method/TranslationTransformationMethod.java
@@ -22,6 +22,7 @@
 import android.util.Log;
 import android.view.View;
 import android.view.translation.TranslationResponseValue;
+import android.view.translation.ViewTranslationRequest;
 import android.view.translation.ViewTranslationResponse;
 import android.widget.TextView;
 
@@ -67,7 +68,8 @@
             Log.w(TAG, "Caller did not enable length changes; not transforming to translated text");
             return source;
         }
-        TranslationResponseValue value = mTranslationResponse.getValue("text");
+        TranslationResponseValue value = mTranslationResponse.getValue(
+                ViewTranslationRequest.ID_TEXT);
         CharSequence translatedText;
         if (value.getStatusCode() == TranslationResponseValue.STATUS_SUCCESS) {
             translatedText = value.getText();
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/AttachedSurfaceControl.java
similarity index 70%
rename from core/java/android/view/ViewRoot.java
rename to core/java/android/view/AttachedSurfaceControl.java
index 3c75598..bcc5b56 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -22,16 +22,19 @@
 /**
  * Provides an interface to the root-Surface of a View Hierarchy or Window. This
  * is used in combination with the {@link android.view.SurfaceControl} API to enable
- * attaching app created SurfaceControl to the ViewRoot's surface hierarchy, and enable
- * SurfaceTransactions to be performed in sync with the ViewRoot drawing. This object
- * is obtained from {@link android.view.View#getViewRoot} and
- * {@link android.view.Window#getViewRoot}. It must be used from the UI thread of
+ * attaching app created SurfaceControl to the SurfaceControl hierarchy used
+ * by the app, and enable SurfaceTransactions to be performed in sync with the
+ * View hierarchy drawing.
+ *
+ * This object is obtained from {@link android.view.View#getRootSurfaceControl} and
+ * {@link android.view.Window#getRootSurfaceControl}. It must be used from the UI thread of
  * the object it was obtained from.
  */
 @UiThread
-public interface ViewRoot {
+public interface AttachedSurfaceControl {
     /**
-     * Create a transaction which will reparent {@param child} to the ViewRoot. See
+     * Create a transaction which will reparent {@param child} to the View hierarchy
+     * root SurfaceControl. See
      * {@link SurfaceControl.Transaction#reparent}. This transacton must be applied
      * or merged in to another transaction by the caller, otherwise it will have
      * no effect.
@@ -42,9 +45,9 @@
     @Nullable SurfaceControl.Transaction buildReparentTransaction(@NonNull SurfaceControl child);
 
     /**
-     * Consume the passed in transaction, and request the ViewRoot to apply it with the
-     * next draw. This transaction will be merged with the buffer transaction from the ViewRoot
-     * and they will show up on-screen atomically synced.
+     * Consume the passed in transaction, and request the View hierarchy to apply it atomically
+     * with the next draw. This transaction will be merged with the buffer transaction from the
+     * ViewRoot and they will show up on-screen atomically synced.
      *
      * This will not cause a draw to be scheduled, and if there are no other changes
      * to the View hierarchy you may need to call {@link android.view.View#invalidate}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c1c892c..acc0fc1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -29599,7 +29599,7 @@
             return mScrollCaptureInternal;
         }
 
-        ViewRoot getViewRoot() {
+        AttachedSurfaceControl getRootSurfaceControl() {
             return mViewRootImpl;
         }
 
@@ -30876,7 +30876,9 @@
 
     /**
      * Called when the content from {@link View#onCreateViewTranslationRequest} had been translated
-     * by the TranslationService.
+     * by the TranslationService. The {@link ViewTranslationResponse} should be saved here so that
+     * the {@link ViewTranslationResponse} can be used to display the translation when the system
+     * calls {@link ViewTranslationCallback#onShowTranslation}.
      *
      * <p> The default implementation will set the ViewTranslationResponse that can be get from
      * {@link View#getViewTranslationResponse}. </p>
@@ -30929,7 +30931,7 @@
      * information, e.g. source spec, target spec.
      * @param requests fill in with {@link ViewTranslationRequest}s for translation purpose.
      */
-    public void dispatchRequestTranslation(@NonNull Map<AutofillId, long[]> viewIds,
+    public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds,
             @NonNull @DataFormat int[] supportedFormats,
             @NonNull TranslationCapability capability,
             @NonNull List<ViewTranslationRequest> requests) {
@@ -31043,17 +31045,17 @@
     }
 
     /**
-     * @return The {@link android.view.ViewRoot} interface for this View. This will only
-     * return a non-null value when called between {@link #onAttachedToWindow} and
-     * {@link #onDetachedFromWindow}.
-     *
-     * The ViewRoot itself is not a View, it is just the interface to the windowing-system
-     * object that contains the entire view hierarchy. For the root View of a given hierarchy
-     * see {@link #getRootView}.
+     * The AttachedSurfaceControl itself is not a View, it is just the interface to the
+     * windowing-system object that contains the entire view hierarchy.
+     * For the root View of a given hierarchy see {@link #getRootView}.
+
+     * @return The {@link android.view.AttachedSurfaceControl} interface for this View.
+     * This will only return a non-null value when called between {@link #onAttachedToWindow}
+     * and {@link #onDetachedFromWindow}.
      */
-    public @Nullable ViewRoot getViewRoot() {
+    public @Nullable AttachedSurfaceControl getRootSurfaceControl() {
         if (mAttachInfo != null) {
-            return mAttachInfo.getViewRoot();
+          return mAttachInfo.getRootSurfaceControl();
         }
         return null;
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index a02281b..4647f47 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -9275,21 +9275,23 @@
     /**
      * {@inheritDoc}
      *
-     * The implementation calls {@link #dispatchRequestTranslation} for all the child views.
+     * The implementation calls {@link #dispatchCreateViewTranslationRequest} for all the child
+     * views.
      */
     @Override
-    public void dispatchRequestTranslation(@NonNull Map<AutofillId, long[]> viewIds,
+    public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds,
             @NonNull @DataFormat int[] supportedFormats,
             @Nullable TranslationCapability capability,
             @NonNull List<ViewTranslationRequest> requests) {
-        super.dispatchRequestTranslation(viewIds, supportedFormats, capability, requests);
+        super.dispatchCreateViewTranslationRequest(viewIds, supportedFormats, capability, requests);
         final int childCount = getChildCount();
         if (childCount == 0) {
             return;
         }
         for (int i = 0; i < childCount; ++i) {
             final View child = getChildAt(i);
-            child.dispatchRequestTranslation(viewIds, supportedFormats, capability, requests);
+            child.dispatchCreateViewTranslationRequest(viewIds, supportedFormats, capability,
+                    requests);
         }
     }
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a06f193..4d1c666 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -224,7 +224,8 @@
  */
 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
 public final class ViewRootImpl implements ViewParent,
-        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks, ViewRoot {
+        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
+        AttachedSurfaceControl {
     private static final String TAG = "ViewRootImpl";
     private static final boolean DBG = false;
     private static final boolean LOCAL_LOGV = false;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 52a09701..5fb4e70 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -2722,11 +2722,12 @@
 
     /**
      * This will be null before a content view is added, e.g. via
-     * {@link #setContentView} or {@link #addContentView}.
+     * {@link #setContentView} or {@link #addContentView}. See
+     * {@link android.view.View#getRootSurfaceControl}.
      *
-     * @return The {@link android.view.ViewRoot} interface for this Window
+     * @return The {@link android.view.AttachedSurfaceControl} interface for this Window
      */
-    public @Nullable ViewRoot getViewRoot() {
+    public @Nullable AttachedSurfaceControl getRootSurfaceControl() {
         return null;
     }
 }
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index 8a2b629..e0526f8 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -466,8 +466,8 @@
                 // traverse the hierarchy to collect ViewTranslationRequests
                 for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
                     View rootView = roots.get(rootNum).getView();
-                    rootView.dispatchRequestTranslation(viewIds, supportedFormats, capability,
-                            requests);
+                    rootView.dispatchCreateViewTranslationRequest(viewIds, supportedFormats,
+                            capability, requests);
                 }
                 mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
                         UiTranslationController::sendTranslationRequest,
diff --git a/core/java/android/view/translation/ViewTranslationRequest.java b/core/java/android/view/translation/ViewTranslationRequest.java
index 2913dfa..00f6ef2 100644
--- a/core/java/android/view/translation/ViewTranslationRequest.java
+++ b/core/java/android/view/translation/ViewTranslationRequest.java
@@ -43,7 +43,7 @@
      * Constant id for the default view text to be translated. This is used by
      * {@link Builder#setValue(String, TranslationRequestValue)}.
      */
-    public static final String ID_TEXT = "text";
+    public static final String ID_TEXT = "android:text";
 
     /**
      * The {@link AutofillId} of the view associated with this request.
@@ -303,7 +303,7 @@
     };
 
     @DataClass.Generated(
-            time = 1617119791798L,
+            time = 1620259482911L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/view/translation/ViewTranslationRequest.java",
             inputSignatures = "public static final  java.lang.String ID_TEXT\nprivate final @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationRequestValue\") java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> mTranslationRequestValues\npublic @android.annotation.NonNull android.view.translation.TranslationRequestValue getValue(java.lang.String)\npublic @android.annotation.NonNull java.util.Set<java.lang.String> getKeys()\npublic @android.annotation.NonNull android.view.autofill.AutofillId getAutofillId()\nprivate static  java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> defaultTranslationRequestValues()\nclass ViewTranslationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> mTranslationRequestValues\nprivate  long mBuilderFieldsSet\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.view.translation.ViewTranslationRequest.Builder setValue(java.lang.String,android.view.translation.TranslationRequestValue)\npublic @android.annotation.NonNull android.view.translation.ViewTranslationRequest build()\n  android.view.translation.ViewTranslationRequest.Builder setTranslationRequestValues(java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue>)\nprivate  void checkNotUsed()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genToString=true, genEqualsHashCode=true, genGetters=false, genHiddenConstructor=true)")
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a1d4822..0bbaac0f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -60,11 +60,13 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
+import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inspector.InspectableProperty;
 import android.view.textclassifier.TextClassifier;
+import android.view.translation.TranslationCapability;
 import android.view.translation.TranslationSpec.DataFormat;
 import android.view.translation.ViewTranslationRequest;
 import android.view.translation.ViewTranslationResponse;
@@ -2869,6 +2871,16 @@
     }
 
     @Override
+    public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds,
+            @NonNull @DataFormat int[] supportedFormats,
+            @Nullable TranslationCapability capability,
+            @NonNull List<ViewTranslationRequest> requests) {
+        super.dispatchCreateViewTranslationRequest(viewIds, supportedFormats, capability, requests);
+        mProvider.getViewDelegate().dispatchCreateViewTranslationRequest(viewIds, supportedFormats,
+                capability, requests);
+    }
+
+    @Override
     public void onVirtualViewTranslationResponses(
             @NonNull LongSparseArray<ViewTranslationResponse> response) {
         mProvider.getViewDelegate().onVirtualViewTranslationResponses(response);
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 8d996ee..f9f823b 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -45,10 +45,12 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
+import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.textclassifier.TextClassifier;
+import android.view.translation.TranslationCapability;
 import android.view.translation.TranslationSpec.DataFormat;
 import android.view.translation.ViewTranslationRequest;
 import android.view.translation.ViewTranslationResponse;
@@ -59,6 +61,7 @@
 
 import java.io.BufferedWriter;
 import java.io.File;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -377,6 +380,14 @@
                         LongSparseArray<ViewTranslationResponse> response) {
         }
 
+        default void dispatchCreateViewTranslationRequest(
+                @NonNull @SuppressWarnings("unused") Map<AutofillId, long[]> viewIds,
+                @NonNull @SuppressWarnings("unused") @DataFormat int[] supportedFormats,
+                @Nullable @SuppressWarnings("unused") TranslationCapability capability,
+                @NonNull @SuppressWarnings("unused") List<ViewTranslationRequest> requests) {
+
+        }
+
         public AccessibilityNodeProvider getAccessibilityNodeProvider();
 
         public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
diff --git a/core/java/android/window/PictureInPictureSurfaceTransaction.java b/core/java/android/window/PictureInPictureSurfaceTransaction.java
index 96a8ac8..dbf7eb3 100644
--- a/core/java/android/window/PictureInPictureSurfaceTransaction.java
+++ b/core/java/android/window/PictureInPictureSurfaceTransaction.java
@@ -24,6 +24,7 @@
 import android.os.Parcelable;
 import android.view.SurfaceControl;
 
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -37,10 +38,11 @@
     public final float mPositionX;
     public final float mPositionY;
 
-    public final float mScaleX;
-    public final float mScaleY;
+    public final float[] mFloat9;
 
+    // Though this can be determined by mFloat9, it's easier to set the value directly
     public final float mRotation;
+
     public final float mCornerRadius;
 
     private final Rect mWindowCrop = new Rect();
@@ -48,21 +50,19 @@
     public PictureInPictureSurfaceTransaction(Parcel in) {
         mPositionX = in.readFloat();
         mPositionY = in.readFloat();
-        mScaleX = in.readFloat();
-        mScaleY = in.readFloat();
+        mFloat9 = new float[9];
+        in.readFloatArray(mFloat9);
         mRotation = in.readFloat();
         mCornerRadius = in.readFloat();
         mWindowCrop.set(Objects.requireNonNull(in.readTypedObject(Rect.CREATOR)));
     }
 
     public PictureInPictureSurfaceTransaction(float positionX, float positionY,
-            float scaleX, float scaleY,
-            float rotation, float cornerRadius,
+            float[] float9, float rotation, float cornerRadius,
             @Nullable Rect windowCrop) {
         mPositionX = positionX;
         mPositionY = positionY;
-        mScaleX = scaleX;
-        mScaleY = scaleY;
+        mFloat9 = Arrays.copyOf(float9, 9);
         mRotation = rotation;
         mCornerRadius = cornerRadius;
         if (windowCrop != null) {
@@ -72,13 +72,14 @@
 
     public PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other) {
         this(other.mPositionX, other.mPositionY,
-                other.mScaleX, other.mScaleY,
-                other.mRotation, other.mCornerRadius,
-                other.mWindowCrop);
+                other.mFloat9, other.mRotation, other.mCornerRadius, other.mWindowCrop);
     }
 
-    public Rect getWindowCrop() {
-        return new Rect(mWindowCrop);
+    /** @return {@link Matrix} from {@link #mFloat9} */
+    public Matrix getMatrix() {
+        final Matrix matrix = new Matrix();
+        matrix.setValues(mFloat9);
+        return matrix;
     }
 
     @Override
@@ -88,8 +89,7 @@
         PictureInPictureSurfaceTransaction that = (PictureInPictureSurfaceTransaction) o;
         return Objects.equals(mPositionX, that.mPositionX)
                 && Objects.equals(mPositionY, that.mPositionY)
-                && Objects.equals(mScaleX, that.mScaleX)
-                && Objects.equals(mScaleY, that.mScaleY)
+                && Arrays.equals(mFloat9, that.mFloat9)
                 && Objects.equals(mRotation, that.mRotation)
                 && Objects.equals(mCornerRadius, that.mCornerRadius)
                 && Objects.equals(mWindowCrop, that.mWindowCrop);
@@ -97,7 +97,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mPositionX, mPositionY, mScaleX, mScaleY,
+        return Objects.hash(mPositionX, mPositionY, Arrays.hashCode(mFloat9),
                 mRotation, mCornerRadius, mWindowCrop);
     }
 
@@ -110,8 +110,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeFloat(mPositionX);
         out.writeFloat(mPositionY);
-        out.writeFloat(mScaleX);
-        out.writeFloat(mScaleY);
+        out.writeFloatArray(mFloat9);
         out.writeFloat(mRotation);
         out.writeFloat(mCornerRadius);
         out.writeTypedObject(mWindowCrop, 0 /* flags */);
@@ -119,11 +118,11 @@
 
     @Override
     public String toString() {
+        final Matrix matrix = getMatrix();
         return "PictureInPictureSurfaceTransaction("
                 + " posX=" + mPositionX
                 + " posY=" + mPositionY
-                + " scaleX=" + mScaleX
-                + " scaleY=" + mScaleY
+                + " matrix=" + matrix.toShortString()
                 + " rotation=" + mRotation
                 + " cornerRadius=" + mCornerRadius
                 + " crop=" + mWindowCrop
@@ -134,15 +133,11 @@
     public static void apply(@NonNull PictureInPictureSurfaceTransaction surfaceTransaction,
             @NonNull SurfaceControl surfaceControl,
             @NonNull SurfaceControl.Transaction tx) {
-        final Matrix matrix = new Matrix();
-        matrix.setScale(surfaceTransaction.mScaleX, surfaceTransaction.mScaleY);
-        if (surfaceTransaction.mRotation != 0) {
-            matrix.postRotate(surfaceTransaction.mRotation);
-        }
+        final Matrix matrix = surfaceTransaction.getMatrix();
         tx.setMatrix(surfaceControl, matrix, new float[9])
                 .setPosition(surfaceControl,
                         surfaceTransaction.mPositionX, surfaceTransaction.mPositionY)
-                .setWindowCrop(surfaceControl, surfaceTransaction.getWindowCrop())
+                .setWindowCrop(surfaceControl, surfaceTransaction.mWindowCrop)
                 .setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius);
     }
 
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 83def0c..14fd4c2 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.media.AudioAttributes;
 import android.media.Ringtone;
@@ -85,6 +86,11 @@
     public static final ComponentName REDUCE_BRIGHT_COLORS_COMPONENT_NAME =
             new ComponentName("com.android.server.accessibility", "ReduceBrightColors");
 
+    // The component name for the sub setting of Accessibility button in Accessibility settings
+    public static final ComponentName ACCESSIBILITY_BUTTON_COMPONENT_NAME =
+            new ComponentName("com.android.server.accessibility", "AccessibilityButton");
+
+
     private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
             .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
@@ -597,7 +603,11 @@
         }
 
         public AlertDialog.Builder getAlertDialogBuilder(Context context) {
-            return new AlertDialog.Builder(context);
+            final boolean inNightMode = (context.getResources().getConfiguration().uiMode
+                    & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+            final int themeId = inNightMode ? R.style.Theme_DeviceDefault_Dialog_Alert :
+                    R.style.Theme_DeviceDefault_Light_Dialog_Alert;
+            return new AlertDialog.Builder(context, themeId);
         }
 
         public Toast makeToastFromText(Context context, CharSequence charSequence, int duration) {
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 4d5b90a..4126801 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -401,8 +401,9 @@
 
         int totalFramesCount = 0;
         long maxFrameTimeNanos = 0;
+        int missedFramesCount = 0;
         int missedAppFramesCount = 0;
-        int missedSfFramesCounts = 0;
+        int missedSfFramesCount = 0;
 
         for (int i = 0; i <= indexOnOrAfterEnd; i++) {
             JankInfo info = mJankInfos.valueAt(i);
@@ -411,17 +412,23 @@
             }
             if (info.surfaceControlCallbackFired) {
                 totalFramesCount++;
+                boolean missedFrame = false;
                 if ((info.jankType & PREDICTION_ERROR) != 0
                         || ((info.jankType & JANK_APP_DEADLINE_MISSED) != 0)) {
                     Log.w(TAG, "Missed App frame:" + info.jankType);
                     missedAppFramesCount++;
+                    missedFrame = true;
                 }
                 if ((info.jankType & DISPLAY_HAL) != 0
                         || (info.jankType & JANK_SURFACEFLINGER_DEADLINE_MISSED) != 0
                         || (info.jankType & JANK_SURFACEFLINGER_GPU_DEADLINE_MISSED) != 0
                         || (info.jankType & SURFACE_FLINGER_SCHEDULING) != 0) {
                     Log.w(TAG, "Missed SF frame:" + info.jankType);
-                    missedSfFramesCounts++;
+                    missedSfFramesCount++;
+                    missedFrame = true;
+                }
+                if (missedFrame) {
+                    missedFramesCount++;
                 }
                 // TODO (b/174755489): Early latch currently gets fired way too often, so we have
                 // to ignore it for now.
@@ -438,10 +445,12 @@
         }
 
         // Log the frame stats as counters to make them easily accessible in traces.
+        Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#missedFrames",
+                missedFramesCount);
         Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#missedAppFrames",
                 missedAppFramesCount);
         Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#missedSfFrames",
-                missedSfFramesCounts);
+                missedSfFramesCount);
         Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#totalFrames",
                 totalFramesCount);
         Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#maxFrameTimeMillis",
@@ -449,7 +458,7 @@
 
         // Trigger perfetto if necessary.
         boolean overMissedFramesThreshold = mTraceThresholdMissedFrames != -1
-                && missedAppFramesCount + missedSfFramesCounts >= mTraceThresholdMissedFrames;
+                && missedFramesCount >= mTraceThresholdMissedFrames;
         boolean overFrameTimeThreshold = mTraceThresholdFrameTimeMillis != -1
                 && maxFrameTimeNanos >= mTraceThresholdFrameTimeMillis * NANOS_IN_MILLISECOND;
         if (overMissedFramesThreshold || overFrameTimeThreshold) {
@@ -460,9 +469,10 @@
                     FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED,
                     mSession.getStatsdInteractionType(),
                     totalFramesCount,
-                    missedAppFramesCount + missedSfFramesCounts,
+                    missedFramesCount,
                     maxFrameTimeNanos,
-                    missedSfFramesCounts);
+                    missedSfFramesCount,
+                    missedAppFramesCount);
             if (mListener != null) {
                 mListener.onCujEvents(mSession, ACTION_METRICS_LOGGED);
             }
@@ -472,7 +482,8 @@
                     + " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
                     + " totalFrames=" + totalFramesCount
                     + " missedAppFrames=" + missedAppFramesCount
-                    + " missedSfFrames=" + missedSfFramesCounts
+                    + " missedSfFrames=" + missedSfFramesCount
+                    + " missedFrames=" + missedFramesCount
                     + " maxFrameTimeMillis=" + maxFrameTimeNanos / NANOS_IN_MILLISECOND);
         }
     }
diff --git a/core/java/com/android/internal/os/BatteryChargeCalculator.java b/core/java/com/android/internal/os/BatteryChargeCalculator.java
index 16f92ef..0690d1f 100644
--- a/core/java/com/android/internal/os/BatteryChargeCalculator.java
+++ b/core/java/com/android/internal/os/BatteryChargeCalculator.java
@@ -42,6 +42,8 @@
                 batteryCapacityMah = batteryStats.getEstimatedBatteryCapacity();
             }
         }
+        builder.setBatteryCapacity(batteryCapacityMah);
+
         final double dischargedPowerLowerBoundMah =
                 batteryStats.getLowDischargeAmountSinceCharge() * batteryCapacityMah / 100.0;
         final double dischargedPowerUpperBoundMah =
diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java
index d139b4f..4979ecb 100644
--- a/core/java/com/android/internal/os/PowerCalculator.java
+++ b/core/java/com/android/internal/os/PowerCalculator.java
@@ -24,6 +24,7 @@
 import android.os.UserHandle;
 import android.util.SparseArray;
 
+import java.io.PrintWriter;
 import java.util.List;
 import java.util.Locale;
 
@@ -157,6 +158,12 @@
         }
     }
 
+    /**
+     * Prints formatted amount of power in milli-amp-hours.
+     */
+    public static void printPowerMah(PrintWriter pw, double powerMah) {
+        pw.print(formatCharge(powerMah));
+    }
 
     /**
      * Converts charge in mAh to string.
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index a6dc4e0..0ea299d 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -70,12 +70,12 @@
 import android.transition.TransitionManager;
 import android.transition.TransitionSet;
 import android.util.AndroidRuntimeException;
+import android.view.AttachedSurfaceControl;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
 import android.util.TypedValue;
-import android.view.ViewRoot;
 import android.view.ContextThemeWrapper;
 import android.view.CrossWindowBlurListeners;
 import android.view.Gravity;
@@ -3984,7 +3984,7 @@
     }
 
     @Override
-    public ViewRoot getViewRoot() {
+    public AttachedSurfaceControl getRootSurfaceControl() {
         return getViewRootImplOrNull();
     }
 }
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index 42fb3f4..72b57ab 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -33,6 +33,7 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
 
 /**
  * Tracks the measured charge consumption of various subsystems according to their
@@ -96,8 +97,10 @@
      * supportedStandardBuckets must be of size {@link #NUMBER_STANDARD_POWER_BUCKETS}.
      * numCustomBuckets >= 0 is the number of (non-standard) custom power buckets on the device.
      */
-    public MeasuredEnergyStats(boolean[] supportedStandardBuckets, String[] customBucketNames) {
-        final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + customBucketNames.length;
+    public MeasuredEnergyStats(@NonNull boolean[] supportedStandardBuckets,
+            @Nullable String[] customBucketNames) {
+        mCustomBucketNames = customBucketNames == null ? new String[0] : customBucketNames;
+        final int numTotalBuckets = NUMBER_STANDARD_POWER_BUCKETS + mCustomBucketNames.length;
         mAccumulatedChargeMicroCoulomb = new long[numTotalBuckets];
         // Initialize to all zeros where supported, otherwise POWER_DATA_UNAVAILABLE.
         // All custom buckets are, by definition, supported, so their values stay at 0.
@@ -106,7 +109,6 @@
                 mAccumulatedChargeMicroCoulomb[stdBucket] = POWER_DATA_UNAVAILABLE;
             }
         }
-        mCustomBucketNames = customBucketNames;
     }
 
     /**
@@ -431,14 +433,22 @@
 
     /** Check if the supported power buckets are precisely those given. */
     public boolean isSupportEqualTo(
-            @NonNull boolean[] queriedStandardBuckets, String[] customBucketNames) {
+            @NonNull boolean[] queriedStandardBuckets, @Nullable String[] customBucketNames) {
+        if (customBucketNames == null) {
+            //In practice customBucketNames should never be null, but sanitize it just to be sure.
+            customBucketNames = new String[0];
+        }
 
         final int numBuckets = getNumberOfIndices();
-        // TODO(b/178504428): Detect whether custom buckets have changed qualitatively, not just
-        //                    quantitatively, and treat as mismatch if so.
-        if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + customBucketNames.length) {
+        final int numCustomBuckets = customBucketNames == null ? 0 : customBucketNames.length;
+        if (numBuckets != NUMBER_STANDARD_POWER_BUCKETS + numCustomBuckets) {
             return false;
         }
+
+        if (!Arrays.equals(mCustomBucketNames, customBucketNames)) {
+            return false;
+        }
+
         for (int stdBucket = 0; stdBucket < NUMBER_STANDARD_POWER_BUCKETS; stdBucket++) {
             if (isStandardBucketSupported(stdBucket) != queriedStandardBuckets[stdBucket]) {
                 return false;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index f19a123..5ba1928 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -271,4 +271,9 @@
      * @param enable {@code true} if enable, otherwise set to {@code false}.
      */
     void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable);
+
+    /**
+     * Triggers a GC in the system and status bar.
+     */
+    void runGcForTest();
 }
diff --git a/core/java/com/android/internal/util/GcUtils.java b/core/java/com/android/internal/util/GcUtils.java
new file mode 100644
index 0000000..e37ba3c
--- /dev/null
+++ b/core/java/com/android/internal/util/GcUtils.java
@@ -0,0 +1,72 @@
+/*
+ * 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.internal.util;
+
+import android.util.Slog;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A helper class to handle gc'ing a process, mainly used for testing.
+ *
+ * @hide
+ */
+public final class GcUtils {
+    private static final String TAG = GcUtils.class.getSimpleName();
+
+    /**
+     * Runs a GC and attempts to wait for finalization.
+     */
+    public static void runGcAndFinalizersSync() {
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+
+        final CountDownLatch fence = new CountDownLatch(1);
+        createFinalizationObserver(fence);
+        try {
+            do {
+                Runtime.getRuntime().gc();
+                Runtime.getRuntime().runFinalization();
+            } while (!fence.await(100, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ex) {
+            throw new RuntimeException(ex);
+        }
+        Slog.v(TAG, "Running gc and finalizers");
+    }
+
+    /**
+     * Create the observer in the scope of a method to minimize the chance that
+     * it remains live in a DEX/machine register at the point of the fence guard.
+     * This must be kept to avoid R8 inlining it.
+     */
+    private static void createFinalizationObserver(CountDownLatch fence) {
+        new Object() {
+            @Override
+            protected void finalize() throws Throwable {
+                try {
+                    fence.countDown();
+                } finally {
+                    super.finalize();
+                }
+            }
+        };
+    }
+
+    // Uninstantiable
+    private GcUtils() {}
+}
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 88e4e35..d2d8220 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -158,7 +158,7 @@
      *     be converted to a string using {@link String#valueOf(Object)}
      * @return the non-null reference that was validated
      * @throws NullPointerException if {@code reference} is null
-     * @deprecated - use {@link java.util.Objects.requireNonNull} instead.
+     * @deprecated - use {@link java.util.Objects#requireNonNull} instead.
      */
     @Deprecated
     @UnsupportedAppUsage
diff --git a/core/java/com/android/internal/widget/EmphasizedNotificationButton.java b/core/java/com/android/internal/widget/EmphasizedNotificationButton.java
index 058a921..4460e4a 100644
--- a/core/java/com/android/internal/widget/EmphasizedNotificationButton.java
+++ b/core/java/com/android/internal/widget/EmphasizedNotificationButton.java
@@ -27,9 +27,7 @@
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
 import android.view.RemotableViewMethod;
-import android.view.ViewGroup;
 import android.widget.Button;
-import android.widget.LinearLayout;
 import android.widget.RemoteViews;
 
 import com.android.internal.R;
@@ -42,8 +40,6 @@
 @RemoteViews.RemoteView
 public class EmphasizedNotificationButton extends Button {
     private final RippleDrawable mRipple;
-    private final int mStrokeWidth;
-    private final int mStrokeColor;
     private boolean mPriority;
 
     public EmphasizedNotificationButton(Context context) {
@@ -63,9 +59,6 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         DrawableWrapper background = (DrawableWrapper) getBackground().mutate();
         mRipple = (RippleDrawable) background.getDrawable();
-        mStrokeWidth = getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.emphasized_button_stroke_width);
-        mStrokeColor = getContext().getColor(com.android.internal.R.color.material_grey_300);
         mRipple.mutate();
     }
 
@@ -82,13 +75,6 @@
         invalidate();
     }
 
-    @RemotableViewMethod
-    public void setHasStroke(boolean hasStroke) {
-        GradientDrawable inner = (GradientDrawable) mRipple.getDrawable(0);
-        inner.setStroke(hasStroke ? mStrokeWidth : 0, mStrokeColor);
-        invalidate();
-    }
-
     /**
      * Sets an image icon which will have its size constrained and will be set to the same color as
      * the text. Must be called after {@link #setTextColor(int)} for the latter to work.
@@ -121,18 +107,13 @@
     }
 
     /**
-     * Changes the LayoutParams.width to WRAP_CONTENT, with the argument representing if this view
-     * is a priority over its peers (which affects weight).
+     * Sets whether this view is a priority over its peers (which affects width).
+     * Specifically, this is used by {@link NotificationActionListLayout} to give this view width
+     * priority ahead of user-defined buttons when allocating horizontal space.
      */
     @RemotableViewMethod
-    public void setWrapModePriority(boolean priority) {
+    public void setIsPriority(boolean priority) {
         mPriority = priority;
-        ViewGroup.LayoutParams layoutParams = getLayoutParams();
-        layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
-        if (layoutParams instanceof LinearLayout.LayoutParams) {
-            ((LinearLayout.LayoutParams) layoutParams).weight = 0;
-        }
-        setLayoutParams(layoutParams);
     }
 
     /**
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 8e6497b..a4d6a60 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -17,11 +17,11 @@
 package com.android.internal.widget;
 
 import android.annotation.DimenRes;
+import android.app.Notification;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
-import android.util.Pair;
 import android.view.Gravity;
 import android.view.RemotableViewMethod;
 import android.view.View;
@@ -43,10 +43,9 @@
     private final int mGravity;
     private int mTotalWidth = 0;
     private int mExtraStartPadding = 0;
-    private ArrayList<Pair<Integer, TextView>> mMeasureOrderTextViews = new ArrayList<>();
+    private ArrayList<TextViewInfo> mMeasureOrderTextViews = new ArrayList<>();
     private ArrayList<View> mMeasureOrderOther = new ArrayList<>();
     private boolean mEmphasizedMode;
-    private boolean mPrioritizedWrapMode;
     private int mDefaultPaddingBottom;
     private int mDefaultPaddingTop;
     private int mEmphasizedHeight;
@@ -70,16 +69,18 @@
         ta.recycle();
     }
 
+    private static boolean isPriority(View actionView) {
+        return actionView instanceof EmphasizedNotificationButton
+                && ((EmphasizedNotificationButton) actionView).isPriority();
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (mEmphasizedMode && !mPrioritizedWrapMode) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
         final int N = getChildCount();
         int textViews = 0;
         int otherViews = 0;
         int notGoneChildren = 0;
+        int priorityChildren = 0;
 
         for (int i = 0; i < N; i++) {
             View c = getChildAt(i);
@@ -90,6 +91,9 @@
             }
             if (c.getVisibility() != GONE) {
                 notGoneChildren++;
+                if (isPriority(c)) {
+                    priorityChildren++;
+                }
             }
         }
 
@@ -103,9 +107,9 @@
         if (!needRebuild) {
             final int size = mMeasureOrderTextViews.size();
             for (int i = 0; i < size; i++) {
-                Pair<Integer, TextView> pair = mMeasureOrderTextViews.get(i);
-                if (pair.first != pair.second.getText().length()) {
+                if (mMeasureOrderTextViews.get(i).needsRebuild()) {
                     needRebuild = true;
+                    break;
                 }
             }
         }
@@ -122,14 +126,19 @@
         int usedWidth = 0;
 
         int measuredChildren = 0;
+        int measuredPriorityChildren = 0;
         for (int i = 0; i < N; i++) {
             // Measure shortest children first. To avoid measuring twice, we approximate by looking
             // at the text length.
-            View c;
+            final boolean isPriority;
+            final View c;
             if (i < otherSize) {
                 c = mMeasureOrderOther.get(i);
+                isPriority = false;
             } else {
-                c = mMeasureOrderTextViews.get(i - otherSize).second;
+                TextViewInfo info = mMeasureOrderTextViews.get(i - otherSize);
+                c = info.mTextView;
+                isPriority = info.mIsPriority;
             }
             if (c.getVisibility() == GONE) {
                 continue;
@@ -143,7 +152,18 @@
                 // measure in the order of (approx.) size, a large view can still take more than its
                 // share if the others are small.
                 int availableWidth = innerWidth - usedWidth;
-                int maxWidthForChild = availableWidth / (notGoneChildren - measuredChildren);
+                int unmeasuredChildren = notGoneChildren - measuredChildren;
+                int maxWidthForChild = availableWidth / unmeasuredChildren;
+                if (isPriority) {
+                    // Priority children get a larger maximum share of the total space:
+                    //  maximum priority share = (nPriority + 1) / (MAX + 1)
+                    int unmeasuredPriorityChildren = priorityChildren - measuredPriorityChildren;
+                    int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren;
+                    int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren
+                            / (Notification.MAX_ACTION_BUTTONS + 1);
+                    int widthAvailableForPriority = availableWidth - widthReservedForOtherChildren;
+                    maxWidthForChild = widthAvailableForPriority / unmeasuredPriorityChildren;
+                }
 
                 usedWidthForChild = innerWidth - maxWidthForChild;
             }
@@ -153,6 +173,9 @@
 
             usedWidth += c.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
             measuredChildren++;
+            if (isPriority) {
+                measuredPriorityChildren++;
+            }
         }
 
         int collapsibleIndent = mCollapsibleIndentDimen == 0 ? 0
@@ -175,13 +198,8 @@
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View c = getChildAt(i);
-            if (c instanceof EmphasizedNotificationButton
-                    && ((EmphasizedNotificationButton) c).isPriority()) {
-                // add with 0 length to ensure that this view is measured before others.
-                mMeasureOrderTextViews.add(Pair.create(0, (TextView) c));
-            } else if (c instanceof TextView && ((TextView) c).getText().length() > 0) {
-                mMeasureOrderTextViews.add(Pair.create(((TextView) c).getText().length(),
-                        (TextView)c));
+            if (c instanceof TextView && ((TextView) c).getText().length() > 0) {
+                mMeasureOrderTextViews.add(new TextViewInfo((TextView) c));
             } else {
                 mMeasureOrderOther.add(c);
             }
@@ -213,10 +231,6 @@
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (mEmphasizedMode && !mPrioritizedWrapMode) {
-            super.onLayout(changed, left, top, right, bottom);
-            return;
-        }
         final boolean isLayoutRtl = isLayoutRtl();
         final int paddingTop = mPaddingTop;
         final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
@@ -293,16 +307,6 @@
     }
 
     /**
-     * When used with emphasizedMode, changes the button sizing behavior to prioritize certain
-     * buttons (which are system generated) to not scrunch, and leave the remaining space for
-     * custom actions.
-     */
-    @RemotableViewMethod
-    public void setPrioritizedWrapMode(boolean prioritizedWrapMode) {
-        mPrioritizedWrapMode = prioritizedWrapMode;
-    }
-
-    /**
      * When buttons are in wrap mode, this is a padding that will be applied at the start of the
      * layout of the actions, but only when those actions would fit with the entire padding
      * visible.  Otherwise, this padding will be omitted entirely.
@@ -353,6 +357,28 @@
         return 0;
     }
 
-    public static final Comparator<Pair<Integer, TextView>> MEASURE_ORDER_COMPARATOR
-            = (a, b) -> a.first.compareTo(b.first);
+    public static final Comparator<TextViewInfo> MEASURE_ORDER_COMPARATOR = (a, b) -> {
+        int priorityComparison = -Boolean.compare(a.mIsPriority, b.mIsPriority);
+        return priorityComparison != 0
+                ? priorityComparison
+                : Integer.compare(a.mTextLength, b.mTextLength);
+    };
+
+    private static final class TextViewInfo {
+        final boolean mIsPriority;
+        final int mTextLength;
+        final TextView mTextView;
+
+        TextViewInfo(TextView textView) {
+            this.mIsPriority = isPriority(textView);
+            this.mTextLength = textView.getText().length();
+            this.mTextView = textView;
+        }
+
+        boolean needsRebuild() {
+            return mTextView.getText().length() != mTextLength
+                    || isPriority(mTextView) != mIsPriority;
+        }
+    }
+
 }
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 315ca2e..5c9999d 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -270,7 +270,28 @@
             metadataSrc->unlock(metaBuffer);
             return;
         }
-        metadataDst->update(entry.tag, entry.data.u8, entry.count);
+        switch (entry.type) {
+            case TYPE_BYTE:
+                metadataDst->update(entry.tag, entry.data.u8, entry.count);
+                break;
+            case TYPE_INT32:
+                metadataDst->update(entry.tag, entry.data.i32, entry.count);
+                break;
+            case TYPE_FLOAT:
+                metadataDst->update(entry.tag, entry.data.f, entry.count);
+                break;
+            case TYPE_INT64:
+                metadataDst->update(entry.tag, entry.data.i64, entry.count);
+                break;
+            case TYPE_DOUBLE:
+                metadataDst->update(entry.tag, entry.data.d, entry.count);
+                break;
+            case TYPE_RATIONAL:
+                metadataDst->update(entry.tag, entry.data.r, entry.count);
+                break;
+            default:
+                ALOGE("%s: Unsupported tag type: %d!", __func__, entry.type);
+        }
     }
     metadataSrc->unlock(metaBuffer);
 }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 5eb1e00..56814c7 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2382,10 +2382,19 @@
     return (jint)nativeToJavaStatus(status);
 }
 
-static jint android_media_AudioSystem_get_FCC_8(JNIEnv *env, jobject thiz) {
+static jint android_media_AudioSystem_getMaxChannelCount(JNIEnv *env, jobject thiz) {
     return FCC_8;
 }
 
+static jint android_media_AudioSystem_getMaxSampleRate(JNIEnv *env, jobject thiz) {
+    // see frameworks/av/services/audiopolicy/common/include/policy.h
+    return 192000; // SAMPLE_RATE_HZ_MAX (for API)
+}
+
+static jint android_media_AudioSystem_getMinSampleRate(JNIEnv *env, jobject thiz) {
+    return 4000; // SAMPLE_RATE_HZ_MIN  (for API)
+}
+
 static jint
 android_media_AudioSystem_setAssistantUid(JNIEnv *env, jobject thiz, jint uid)
 {
@@ -2810,14 +2819,18 @@
         (void *)android_media_AudioSystem_eventHandlerFinalize},
 };
 
-static const JNINativeMethod gGetFCC8Methods[] = {
-    {"native_get_FCC_8", "()I", (void *)android_media_AudioSystem_get_FCC_8},
+static const JNINativeMethod gFrameworkCapabilities[] = {
+        {"native_getMaxChannelCount", "()I", (void *)android_media_AudioSystem_getMaxChannelCount},
+        {"native_getMaxSampleRate", "()I", (void *)android_media_AudioSystem_getMaxSampleRate},
+        {"native_getMinSampleRate", "()I", (void *)android_media_AudioSystem_getMinSampleRate},
 };
 
 int register_android_media_AudioSystem(JNIEnv *env)
 {
     // This needs to be done before hooking up methods AudioTrackRoutingProxy (below)
-    RegisterMethodsOrDie(env, kClassPathName, gGetFCC8Methods, NELEM(gGetFCC8Methods));
+    // as the calls are performed in the static initializer of AudioSystem.
+    RegisterMethodsOrDie(env, kClassPathName, gFrameworkCapabilities,
+                         NELEM(gFrameworkCapabilities));
 
     jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
     gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
diff --git a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
index 980e12d..83e2f2b 100644
--- a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
+++ b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
@@ -31,7 +31,7 @@
 }
 
 static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) {
-    return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd));
+    return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFd(env, javaFd));
 }
 
 static const JNINativeMethod gNetworkUtilMethods[] = {
diff --git a/core/res/Android.bp b/core/res/Android.bp
index b988b5a..6063062 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -100,8 +100,7 @@
         + "RES_DIR=$$(dirname $$(dirname $${INPUTS[0]})) && "
         + "mkdir -p $$RES_DIR/values && "
         + "cp $${INPUTS[1]} $$RES_DIR/values && "
-        + "$(location soong_zip) -o $(out) -C $$RES_DIR -D $$RES_DIR && "
-        + "cp $(out) ."
+        + "$(location soong_zip) -o $(out) -C $$RES_DIR -D $$RES_DIR"
 }
 
 android_app {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4e7dd91..ffb8d1d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -696,6 +696,8 @@
     <protected-broadcast android:name="android.scheduling.action.REBOOT_READY" />
     <protected-broadcast android:name="android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED" />
 
+    <protected-broadcast android:name="android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
diff --git a/core/res/res/drawable/btn_notification_emphasized.xml b/core/res/res/drawable/btn_notification_emphasized.xml
index ad68054..63707ab 100644
--- a/core/res/res/drawable/btn_notification_emphasized.xml
+++ b/core/res/res/drawable/btn_notification_emphasized.xml
@@ -24,13 +24,11 @@
         <item>
             <shape android:shape="rectangle">
                 <corners android:radius="@dimen/notification_action_button_radius" />
-                <padding android:left="@dimen/button_padding_horizontal_material"
+                <padding android:left="12dp"
                          android:top="@dimen/button_padding_vertical_material"
-                         android:right="@dimen/button_padding_horizontal_material"
+                         android:right="12dp"
                          android:bottom="@dimen/button_padding_vertical_material" />
                 <solid android:color="@color/white" />
-                <stroke android:width="@dimen/emphasized_button_stroke_width"
-                        android:color="@color/material_grey_300"/>
             </shape>
         </item>
     </ripple>
diff --git a/core/res/res/layout/notification_material_action_emphasized.xml b/core/res/res/layout/notification_material_action_emphasized.xml
index cd1f1ab..ea84185 100644
--- a/core/res/res/layout/notification_material_action_emphasized.xml
+++ b/core/res/res/layout/notification_material_action_emphasized.xml
@@ -18,10 +18,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@style/NotificationEmphasizedAction"
     android:id="@+id/action0"
-    android:layout_width="match_parent"
+    android:layout_width="wrap_content"
     android:layout_height="match_parent"
     android:layout_marginStart="12dp"
-    android:layout_weight="1"
     android:drawablePadding="6dp"
     android:gravity="center"
     android:textColor="@color/notification_default_color"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index da2ea3e..73adeaa 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Teks na knipbord gekopieër."</string>
     <string name="copied" msgid="4675902854553014676">"Gekopieer"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> het uit <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> geplak"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> van jou knipbord af geplak"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> het teks geplak wat jy gekopieer het"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> het \'n prent geplak wat jy gekopieer het"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> het inhoud geplak wat jy gekopieer het"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Berei tans <xliff:g id="APPNAME">%1$s</xliff:g> voor."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Begin programme."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Voltooi herlaai."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Skakel skerm af?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Jy het die aan/af-skakelaar gedruk terwyl jy jou vingerafdruk gestel het.\n\nDit skakel gewoonlik jou skerm af."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Skakel af"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Kanselleer"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> loop"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Tik om na die speletjie terug te keer"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Kies speletjie"</string>
@@ -1875,10 +1870,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Opgedateer deur jou administrateur"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Uitgevee deur jou administrateur"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte, sekere kenmerke en sommige netwerkverbindings af.\n\n"<annotation id="url">"Kom meer te wete"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte, sekere kenmerke en sommige netwerkverbindings af"</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys voordat jy op hulle tik nie."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Skakel Databespaarder aan?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Skakel aan"</string>
@@ -1981,10 +1974,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> is nie nou onmiddellik beskikbaar nie. Dit word bestuur deur <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"Kom meer te wete"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Hervat program"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"Skakel werkprogramme aan?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Kry toegang tot jou werkprogramme en -kennisgewings"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Skakel aan"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Program is nie beskikbaar nie"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nie op die oomblik beskikbaar nie."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index c1a8b1e..f8ff934 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"ፅሁፍ ወደ ቅንጥብ ሰሌዳ ተገልብጧል።"</string>
     <string name="copied" msgid="4675902854553014676">"ተቀድቷል"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ከ <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> ተለጥፏል"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ከእርስዎ ቅንጥብ ሰሌዳ ተለጥፏል"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> እርስዎ የቀዱትን ጽሑፍ ለጥፏል"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> እርስዎ የቀዱትን ምስል ለጥፏል"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> እርስዎ የቀዱትን ይዘት ለጥፏል"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g>ን ማዘጋጀት።"</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"መተግበሪያዎችን በማስጀመር ላይ፡፡"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"አጨራረስ ማስነሻ፡፡"</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"ማያ ገጽ ይጥፋ?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"የጣት አሻራዎን ሲያዋቅሩ የኃይል አዝራሩን ተጫንተውታል። \n\n ይህ አብዛኛው ጊዜ ማያ ገጽዎን ያጠፈዋል።"</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"አጥፋ"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"ይቅር"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> አሂድ"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"ወደ ጨዋታ ለመመለስ መታ ያድርጉ"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"ጨዋታ ይምረጡ"</string>
@@ -1718,8 +1713,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"አቋራጭ ይጠቀሙ"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"ተቃራኒ ቀለም"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"የቀለም ማስተካከያ"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"የአንድ እጅ ሁነታ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ተጨማሪ ደብዛዛ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> በርቷል።"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"የድምፅ ቁልፎችን ይዟል። <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ጠፍተዋል።"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index fa5f8e4..8101c28 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"শ্বৰ্টকাট ব্যৱহাৰ কৰক"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"ৰং বিপৰীতকৰণ"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"ৰং শুধৰণি"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এখন হাতেৰে ব্যৱহাৰ কৰাৰ ম’ড"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"এক্সট্ৰা ডিম"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ভলিউম কীসমূহ ধৰি ৰাখক। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অন কৰা হ\'ল।"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ভলিউম কী ধৰি ৰাখিছিল। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> অফ কৰা হ\'ল।"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b682a16..2681451 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1025,8 +1025,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Tekst je kopiran u privremenu memoriju."</string>
     <string name="copied" msgid="4675902854553014676">"Kopirano je"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Aplikacija<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je nalepila podatke iz aplikacije <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Sadržaj aplikacije <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je nalepljen u privr. memoriju"</string>
     <string name="pasted_text" msgid="4298871641549173733">"Aplikacija<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je nalepila tekst koji ste kopirali"</string>
     <string name="pasted_image" msgid="4729097394781491022">"Aplikacija<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je nalepila sliku koju ste kopirali"</string>
     <string name="pasted_content" msgid="646276353060777131">"Aplikacija<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je nalepila sadržaj koji ste kopirali"</string>
@@ -1280,14 +1279,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Priprema se <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Pokretanje aplikacija."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Završavanje pokretanja."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Želite da isključite ekran?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Pritisli ste dugme za uključivanje tokom podešavanja otiska prsta.\n\nTako se najčešće isključuje ekran."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Isključi"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Otkaži"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je pokrenuta"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Dodirnite da biste se vratili u igru"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Odaberite igru"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 2999945c3..9dedb88 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"ক্লিপবোর্ডে পাঠ্য অনুলিপি করা হয়েছে৷"</string>
     <string name="copied" msgid="4675902854553014676">"কপি করা হয়েছে"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> থেকে কপি করা ডেটা <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>-এ পেস্ট করা হয়েছে"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"আপনার ক্লিপবোর্ড থেকে <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> পেস্ট করা হয়েছে"</string>
     <string name="pasted_text" msgid="4298871641549173733">"আপনার কপি করা টেক্সট <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> অ্যাপ পেস্ট করেছে"</string>
     <string name="pasted_image" msgid="4729097394781491022">"আপনার কপি করা ছবি <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> অ্যাপ পেস্ট করেছে"</string>
     <string name="pasted_content" msgid="646276353060777131">"আপনার কপি করা কন্টেন্ট <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> অ্যাপ পেস্ট করেছে"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> প্রস্তুত করা হচ্ছে৷"</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"অ্যাপ্লিকেশানগুলি শুরু করা হচ্ছে৷"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"চালু করা সম্পূর্ণ হচ্ছে৷"</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"স্ক্রিন বন্ধ করবেন?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"আপনার আঙ্গুলের ছাপ সেট আপ করার সময়, পাওয়ার বোতাম প্রেস করেছিলেন।\n\nএর ফলে সাধারণত আপনার স্ক্রিন বন্ধ হয়ে যায়।"</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"বন্ধ করুন"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"বাতিল করুন"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> চলছে"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"গেমে ফিরে আসতে ট্যাপ করুন"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"গেম বেছে নিন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 96cec5a..c918d8c 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1025,8 +1025,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Tekst kopiran u međumemoriju."</string>
     <string name="copied" msgid="4675902854553014676">"Kopirano"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Aplikacija <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je zalijepljena iz aplikacije <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Aplikacija <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je zalijepila sadržaj iz međumemorije"</string>
     <string name="pasted_text" msgid="4298871641549173733">"Aplikacija <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je zalijepila kopirani tekst"</string>
     <string name="pasted_image" msgid="4729097394781491022">"Aplikacija <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je zalijepila kopiranu sliku"</string>
     <string name="pasted_content" msgid="646276353060777131">"Aplikacija <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> je zalijepila kopirani sadržaj"</string>
@@ -1280,14 +1279,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Pripremanje aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Pokretanje aplikacija."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Pokretanje pri kraju."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Isključiti ekran?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Prilikom postavljanja otiska prsta, pritisnuli ste dugme za uključivanje.\n\nTime se obično isključuje ekran."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Isključi"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Otkaži"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Pokrenuta je aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Dodirnite za povratak u igru"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Odaberite igru"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 77b7911..402402f 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Text copiat al Porta-retalls."</string>
     <string name="copied" msgid="4675902854553014676">"S\'ha copiat"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha enganxat dades de: <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha enganxat contingut del porta-retalls"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha enganxat text que has copiat"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha enganxat una imatge que has copiat"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha enganxat contingut que has copiat"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"S\'està preparant <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"S\'estan iniciant les aplicacions."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"S\'està finalitzant l\'actualització."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Vols apagar la pantalla?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Mentre configuraves la teva empremta digital has premut el botó d\'engegada.\n\nAixò normalment apaga la pantalla."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Desactiva"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Cancel·la"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> s\'està executant"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Toca per tornar al joc"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Tria el joc"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 7e40710..17ddb0e 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1028,8 +1028,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Text byl zkopírován do schránky."</string>
     <string name="copied" msgid="4675902854553014676">"Zkopírováno"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Aplikace <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> vložila data z aplikace <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Aplikace <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> vložila obsah ze schránky"</string>
     <string name="pasted_text" msgid="4298871641549173733">"Aplikace <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> vložila zkopírovaný text"</string>
     <string name="pasted_image" msgid="4729097394781491022">"Aplikace <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> vložila zkopírovaný obrázek"</string>
     <string name="pasted_content" msgid="646276353060777131">"Aplikace <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> vložila zkopírovaný obsah"</string>
@@ -1300,14 +1299,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Příprava aplikace <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Spouštění aplikací."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Dokončování inicializace."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Vypnout obrazovku?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Při nastavování otisku prstu jste stiskli vypínač.\n\nTen obvykle vypne obrazovku."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Vypnout"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Zrušit"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Běží aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Klepnutím se vrátíte do hry"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Vyberte hru"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 697071c..d4aced53 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Teksten er kopieret til udklipsholderen."</string>
     <string name="copied" msgid="4675902854553014676">"Kopieret"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> indsatte indhold fra <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> indsatte indhold fra din udklipsholder"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> indsatte tekst, som du har kopieret"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> indsatte et billede, som du har kopieret"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> indsatte indhold, som du har kopieret"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Forbereder <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Åbner dine apps."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Gennemfører start."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Vil du slukke skærmen?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Ved konfigurationen af dit fingeraftryk trykkede du på afbryderknappen.\n\nDet medfører normalt, at din skærm slukkes."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Sluk"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Annuller"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> er i gang"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Tryk for at vende tilbage til spillet"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Vælg et spil"</string>
@@ -1875,10 +1870,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Opdateret af din administrator"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet af din administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"Batterisparefunktionen aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden og visse visuelle effekter, funktioner og netværksforbindelser.\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"Batterisparefunktionen aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden og visse visuelle effekter, funktioner og netværksforbindelser."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du aktivere Datasparefunktion?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivér"</string>
@@ -1981,10 +1974,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgængelig lige nu. Dette administreres af <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"Få flere oplysninger"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Afslut pause for app"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"Vil du aktivere arbejdsapps?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Få adgang til dine arbejdsapps og notifikationer"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Slå til"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgængelig"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgængelig lige nu."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8575a1d..bd01896 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Verknüpfung verwenden"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Farbumkehr"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Farbkorrektur"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Einhandmodus"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradunkel"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist aktiviert."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Lautstärketasten wurden gedrückt gehalten. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ist deaktiviert."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index d807093..1f11664 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Το κείμενο αντιγράφηκε στο πρόχειρο."</string>
     <string name="copied" msgid="4675902854553014676">"Αντιγράφηκε"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Η εφαρμογή <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> έκανε επικόλληση από την εφαρμογή <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Η εφαρμογή <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> επικόλλησε δεδομένα από το πρόχειρο"</string>
     <string name="pasted_text" msgid="4298871641549173733">"Η εφαρμογή <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> επικόλλησε το κείμενο που αντιγράψατε"</string>
     <string name="pasted_image" msgid="4729097394781491022">"Η εφαρμογή <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> επικόλλησε την εικόνα που αντιγράψατε"</string>
     <string name="pasted_content" msgid="646276353060777131">"Η εφαρμογή <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> επικόλλησε περιεχόμενο που αντιγράψατε"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Προετοιμασία <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Έναρξη εφαρμογών."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Ολοκλήρωση εκκίνησης."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Απενεργοποίηση οθόνης;"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Κατά τη ρύθμιση του δακτυλικού σας αποτυπώματος, πατήσατε το κουμπί λειτουργίας.\n\nΑυτό απενεργοποιεί συνήθως την οθόνη."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Απενεργοποίηση"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Ακύρωση"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Πατήστε για να επιστρέψετε στο παιχνίδι"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Επιλέξτε παιχνίδι"</string>
@@ -1718,8 +1713,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Χρήση συντόμευσης"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Αντιστροφή χρωμάτων"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Διόρθωση χρωμάτων"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Λειτουργία ενός χεριού"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Επιπλέον μείωση φωτεινότητας"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ενεργοποιήθηκε."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Τα πλήκτρα έντασης είναι πατημένα. <xliff:g id="SERVICE_NAME">%1$s</xliff:g>: απενεργοποιημένο"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 146df87..624a678 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Texto copiado en el portapapeles."</string>
     <string name="copied" msgid="4675902854553014676">"Copiado"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> pegó contenido de <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> pegó información del portapapeles"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> accedió a texto del portapapeles"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> accedió a una imagen del portapapeles"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> accedió al contenido del portapapeles"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Iniciando aplicaciones"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Finalizando el inicio"</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"¿Quieres apagar la pantalla?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Al configurar tu huella dactilar, presionaste el botón de encendido.\n\nPor lo general, esta acción apaga la pantalla."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Apagar"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Cancelar"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Presiona para volver al juego"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Elige un juego"</string>
@@ -1874,10 +1869,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Tu administrador actualizó este paquete"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Tu administrador borró este paquete"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"El Ahorro de batería activa el Tema oscuro y desactiva o restringe la actividad en segundo plano, algunos efectos visuales, algunas conexiones de red y otras funciones determinadas.\n\n"<annotation id="url">"Más información"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"El Ahorro de batería activa el Tema oscuro y desactiva o restringe la actividad en segundo plano, algunos efectos visuales, algunas conexiones de red y otras funciones determinadas."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, el modo Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"¿Deseas activar Ahorro de datos?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
@@ -1980,10 +1973,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no está disponible en este momento. Esta opción se administra en <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"Más información"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Reanudar app"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"¿Activar apps de trabajo?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Obtén acceso a tus apps de trabajo y notificaciones"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index abcb432..00a7522 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Texto copiado al portapapeles."</string>
     <string name="copied" msgid="4675902854553014676">"Copiado"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha pegado contenido de <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Se ha pegado <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> desde el portapapeles"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha pegado texto que has copiado"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha pegado una imagen que has copiado"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha pegado contenido que has copiado"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Iniciando aplicaciones"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Finalizando inicio..."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"¿Apagar pantalla?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Has pulsado el botón de encendido mientras configurabas tu huella digital.\n\nAl hacer esto, se suele apagar la pantalla."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Desactivar"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Cancelar"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Toca para volver al juego"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Elegir juego"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 679b491..428832d 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Testua arbelean kopiatu da."</string>
     <string name="copied" msgid="4675902854553014676">"Kopiatu da"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> aplikaziotik itsatsi da <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> aplikazioak arbeletik itsatsi du"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> aplikazioak kopiatu duzun testua itsatsi du"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> aplikazioak kopiatu duzun irudia itsatsi du"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> aplikazioak kopiatu duzun edukia itsatsi du"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> prestatzen."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Aplikazioak abiarazten."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Bertsio-berritzea amaitzen."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Pantaila itzali nahi duzu?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Hatz-marka konfiguratzean, etengailua sakatu duzu.\n\nNormalean, horren ondorioz pantaila itzali egiten da."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Desaktibatu"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Utzi"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> abian da"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Sakatu jokora itzultzeko"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Aukeratu joko bat"</string>
@@ -1718,8 +1713,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Erabili lasterbidea"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Koloreen alderantzikatzea"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Koloreen zuzenketa"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Esku bakarreko modua"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Are ilunago"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> aktibatu egin da."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Bolumen-botoiak sakatuta eduki direnez, <xliff:g id="SERVICE_NAME">%1$s</xliff:g> desaktibatu egin da."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 68c5b0d..b66ad5a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"متن در بریده‌دان کپی شد."</string>
     <string name="copied" msgid="4675902854553014676">"کپی شد"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> از <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> جای‌گذاری کرد"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> از بریده‌دان جای‌گذاری کرد"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> نوشتاری را که کپی کردید جای‌گذاری کرد"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> تصویری را که کپی کردید جای‌گذاری کرد"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> محتوایی را که کپی کردید جای‌گذاری کرد"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"آماده‌سازی <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"درحال آغاز کردن برنامه‌ها."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"درحال اتمام راه‌اندازی."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"صفحه‌نمایش خاموش شود؟"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"هنگام راه‌اندازی اثر انگشتتان، دکمه روشن/ خاموش را فشار دادید.\n\nاین کار معمولاً صفحه‌نمایش را خاموش می‌کند."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"خاموش شود"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"لغو شود"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> در حال اجرا"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"برای برگشت به بازی، ضربه بزنید"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"انتخاب بازی"</string>
@@ -1875,10 +1870,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم به‌روزرسانی شد"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"توسط سرپرست سیستم حذف شد"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"تأیید"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"«بهینه‌سازی باتری» «طرح زمینه تیره» را روشن می‌کند و فعالیت پس‌زمینه، برخی از جلوه‌های بصری، ویژگی‌هایی خاص، و برخی از اتصال‌های شبکه را محدود یا خاموش می‌کند.\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"«بهینه‌سازی باتری» «طرح زمینه تیره» را روشن می‌کند و فعالیت پس‌زمینه، برخی از جلوه‌های بصری، ویژگی‌هایی خاص، و برخی از اتصال‌های شبکه را محدود یا خاموش می‌کند."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"برای کمک به کاهش مصرف داده، «صرفه‌جویی داده» از ارسال و دریافت داده در پس‌زمینه در بعضی برنامه‌ها جلوگیری می‌کند. برنامه‌ای که درحال‌حاضر استفاده می‌کنید می‌تواند به داده‌ها دسترسی داشته باشد اما دفعات دسترسی آن محدود است. این می‌تواند به این معنی باشد که، برای مثال، تصاویر تازمانی‌که روی آن‌ها ضربه نزنید نشان داده نمی‌شوند."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"«صرفه‌جویی داده» روشن شود؟"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"روشن کردن"</string>
@@ -1981,10 +1974,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> درحال‌حاضر در دسترس نیست. <xliff:g id="APP_NAME_1">%2$s</xliff:g> آن را مدیریت می‌کند."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"بیشتر بدانید"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"لغو توقف موقت برنامه"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"برنامه‌های کاری روشن شود؟"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"دسترسی به اعلان‌ها و برنامه‌های کاری"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"روشن کردن"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"برنامه در دسترس نیست"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحال‌حاضر در دسترس نیست."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index ee6e934..28990b4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Le texte a été copié dans le presse-papier."</string>
     <string name="copied" msgid="4675902854553014676">"Copie effectuée"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> collé depuis <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> a copié des données depuis le presse-papiers"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> a collé du texte que vous avez copié"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> a collé une image que vous avez copiée"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> a collé le contenu que vous avez copié"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Préparation de <xliff:g id="APPNAME">%1$s</xliff:g> en cours…"</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Lancement des applications…"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Finalisation de la mise à jour."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Éteindre l\'écran ?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Vous avez appuyé sur le bouton Marche/Arrêt pendant la configuration de votre empreinte digitale.\n\nCela éteint généralement l\'écran."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Éteindre"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Annuler"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Appuyez pour revenir au jeu"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Choisir un jeu"</string>
@@ -1718,8 +1713,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Utiliser le raccourci"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversion des couleurs"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Correction des couleurs"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode une main"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Encore moins lumineux"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> activé."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Touches de volume appuyées de manière prolongée. Service <xliff:g id="SERVICE_NAME">%1$s</xliff:g> désactivé."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 4bb6aa6..e2bd3cb 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"O texto copiouse no portapapeis."</string>
     <string name="copied" msgid="4675902854553014676">"Copiuse"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> pegou contido procedente de <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> pegou contido do portapapeis"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> pegou texto que copiaches"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> pegou unha imaxe que copiaches"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> pegou contido que copiaches"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Iniciando aplicacións."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Está finalizando o arranque"</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Queres apagar a pantalla?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Premiches o botón de acendido mentres configurabas a impresión dixital.\n\nAo realizar esta acción, normalmente apágase a pantalla."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Apagar"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Cancelar"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> está en execución"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Toca para volver ao xogo"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Escolle un xogo"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 20da0ac..b4594e1 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"लेख को क्‍लिपबोर्ड पर कॉपी किया गया."</string>
     <string name="copied" msgid="4675902854553014676">"कॉपी किया गया"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> से कॉपी किए गए डेटा को <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> में चिपकाया गया है"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ने क्लिपबोर्ड में मौजूद डेटा कॉपी करके चिपकाया"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ने आपका कॉपी किया हुआ टेक्स्ट चिपका दिया है"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ने आपकी कॉपी की हुई इमेज चिपका दी है"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ने आपका कॉपी किया हुआ कॉन्टेंट चिपका दिया है"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> तैयार हो रहा है."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"ऐप्स  प्रारंभ होने वाले हैं"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"बूट खत्म हो रहा है."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"स्क्रीन बंद करें?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"अपना फ़िंगरप्रिंट सेट अप करते समय, आपने पावर बटन दबाया.\n\nआम तौर पर, इससे स्क्रीन बंद हो जाती है."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"बंद करें"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"अभी नहीं"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> चल रही है"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"गेम पर वापस जाने के लिए टैप करें"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"गेम चुनें"</string>
@@ -1718,8 +1713,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"शॉर्टकट का उपयोग करें"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"रंग बदलने की सुविधा"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"रंग में सुधार करने की सुविधा"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"वन-हैंडेड मोड"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को चालू कर दिया गया."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"आवाज़ कम-ज़्यादा करने वाले दोनों बटन दबाकर रखें. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> को बंद कर दिया गया."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index be2307b..8759f7a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1025,8 +1025,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Tekst kopiran u međuspremnik."</string>
     <string name="copied" msgid="4675902854553014676">"Kopirano"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"U aplikaciji <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> zalijepljen je sadržaj aplikacije <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Zalijepljen je sadržaj aplikacije <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>"</string>
     <string name="pasted_text" msgid="4298871641549173733">"Aplikacija <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> zalijepila je tekst koji ste kopirali"</string>
     <string name="pasted_image" msgid="4729097394781491022">"Aplikacija <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> zalijepila je sliku koju ste kopirali"</string>
     <string name="pasted_content" msgid="646276353060777131">"Aplikacija <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> zalijepila je ono što ste kopirali"</string>
@@ -1280,14 +1279,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Pripremanje aplikacije <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Pokretanje aplikacija."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Završetak inicijalizacije."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Isključiti zaslon?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Prilikom postavljanja otiska prsta pritisnuli ste tipku za uključivanje/isključivanje.\n\nTom se radnjom obično isključuje zaslon."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Isključi"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Odustani"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Izvodi se <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Dodirnite za povratak na igru"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Odabir igre"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index c57d555..dd4afa53 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"A szöveg bemásolva a vágólapra."</string>
     <string name="copied" msgid="4675902854553014676">"Átmásolva"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"A(z) <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> tartalmat másolt vágólapra a(z) <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> appból"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"A(z) <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> beillesztett a vágólapról"</string>
     <string name="pasted_text" msgid="4298871641549173733">"A(z) <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> beillesztette a másolt szöveget"</string>
     <string name="pasted_image" msgid="4729097394781491022">"A(z) <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> beillesztette a másolt képet"</string>
     <string name="pasted_content" msgid="646276353060777131">"A(z) <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> beillesztette a másolt tartalmat"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> előkészítése."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Kezdő alkalmazások."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Rendszerindítás befejezése."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Kikapcsolja a képernyőt?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Ujjlenyomata beállítása közben megnyomta a bekapcsológombot.\n\nEz általában kikapcsolja a képernyőt."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Kikapcsolás"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Mégse"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> fut"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Koppintson ide a játékhoz való visszatéréshez"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Játék kiválasztása"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 0c653a1..990f94d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gunakan Pintasan"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Inversi Warna"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Koreksi Warna"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode satu tangan"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra redup"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> diaktifkan."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Tombol volume ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dinonaktifkan."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index f4055ce..ba889b6 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Texti afritaður á klippiborð."</string>
     <string name="copied" msgid="4675902854553014676">"Afritað"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> límt úr <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> límdi af klippiborðinu"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> límdi texta sem þú afritaðir"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> límdi mynd sem þú afritaðir"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> límdi efni sem þú afritaðir"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Undirbýr <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Ræsir forrit."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Lýkur ræsingu."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Slökkva á skjá?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Þú ýttir á aflrofann þegar þú varst að skrá fingrafarið þitt.\n\nYfirleitt slekkur það á skjánum."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Slökkva"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Hætta við"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> er í gangi"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Ýttu til að fara aftur í leik"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Velja leik"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 35980c3..411c4e1 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Testo copiato negli appunti."</string>
     <string name="copied" msgid="4675902854553014676">"Copia eseguita"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Dati dell\'app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> incollati dall\'app <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"L\'app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha incollato dati dagli appunti"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha incollato il testo che hai copiato"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha incollato un\'immagine che hai copiato"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ha incollato i contenuti che hai copiato"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> in preparazione."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Avvio app."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Conclusione dell\'avvio."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Vuoi disattivare lo schermo?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Durante la configurazione della tua impronta hai premuto il tasto di accensione.\n\nGeneralmente questa azione comporta la disattivazione dello schermo."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Disattiva"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Annulla"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> in esecuzione"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Tocca per tornare al gioco"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Scegli gioco"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 5a7eba3..7238cde 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"テキストをクリップボードにコピーしました。"</string>
     <string name="copied" msgid="4675902854553014676">"コピーしました"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> から <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> に貼り付けました"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> にクリップボードから貼り付けました"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> がクリップボード内のテキストを貼り付けました"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> がクリップボード内の画像を貼り付けました"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> がクリップボード内のコンテンツを貼り付けました"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g>をペア設定しています。"</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"アプリを起動しています。"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"ブートを終了しています。"</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"画面を OFF にしますか?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"指紋の設定中に電源ボタンが押されました。\n\n通常、この操作により画面が OFF になります。"</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"OFF にする"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"キャンセル"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g>を実行中"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"タップするとゲームに戻ります"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"ゲームの選択"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 8a9547b..a2b337d 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"მალსახმობის გამოყენება"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"ფერთა ინვერსია"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"ფერთა კორექცია"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ცალი ხელის რეჟიმი"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"დამატებითი დაბინდვა"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ჩართულია."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ხანგრძლივად დააჭირეთ ხმის ღილაკებს. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> გამორთულია."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index ea6d6de..31f2b50 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"បាន​ចម្លង​អត្ថបទ​ទៅ​ក្ដារ​តម្បៀត​ខ្ទាស់។"</string>
     <string name="copied" msgid="4675902854553014676">"បា​នចម្លង"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> បានដាក់ចូលពី <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> បានដាក់ចូល​ពីឃ្លីបបត​របស់អ្នក"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> បានដាក់ចូល​អត្ថបទ​ដែលអ្នក​បានចម្លង"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> បានដាក់ចូល​រូបភាព​ដែលអ្នក​បានចម្លង"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> បានដាក់ចូល​ខ្លឹមសារ​ដែលអ្នក​បានចម្លង"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"កំពុងរៀបចំ <xliff:g id="APPNAME">%1$s</xliff:g>។"</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"ចាប់ផ្ដើម​កម្មវិធី។"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"បញ្ចប់​ការ​ចាប់ផ្ដើម។"</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"បិទ​អេក្រង់ឬ?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"នៅពេលរៀបចំ​ស្នាមម្រាមដៃ​របស់អ្នក អ្នកបានចុច​ប៊ូតុងថាមពល។\n\nជាធម្មតា ការធ្វើបែបនេះ​បិទអេក្រង់​របស់អ្នក។"</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"បិទ"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"បោះបង់"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> កំពុង​ដំណើរការ"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"ចុច​ដើម្បី​ត្រឡប់​ទៅ​ហ្គេមវិញ"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"ជ្រើសរើស​ហ្គេម"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 126e1f4..f3d0d58 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1875,10 +1875,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್‌ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ಸರಿ"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು, ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಮತ್ತು ಇತರ ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ.\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು, ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳು ಮತ್ತು ಇತರ ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"ಡೇಟಾ ಸೇವರ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"ಆನ್‌ ಮಾಡಿ"</string>
@@ -1981,10 +1979,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ಅಪ್ಲಿಕೇಶನ್‌ ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ. ಇದನ್ನು <xliff:g id="APP_NAME_1">%2$s</xliff:g> ನಲ್ಲಿ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ಆ್ಯಪ್ ವಿರಾಮ ನಿಲ್ಲಿಸಿ"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"ಕೆಲಸ ಆ್ಯಪ್‌ಗಳನ್ನು ಆನ್ ಮಾಡಬೇಕೆ?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"ನಿಮ್ಮ ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಪಡೆಯಿರಿ"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"ಆನ್‌ ಮಾಡಿ"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"ಆ್ಯಪ್ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಇದೀಗ ಲಭ್ಯವಿಲ್ಲ."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index b0782ab..667057f3 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"ສຳເນົາຂໍ້ຄວາມໃສ່ຄລິບບອດແລ້ວ."</string>
     <string name="copied" msgid="4675902854553014676">"ສຳເນົາແລ້ວ"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"ວາງ <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ຈາກ <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> ແລ້ວ"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ວາງຈາກຄລິບບອດຂອງທ່ານແລ້ວ"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ວາງຂໍ້ຄວາມທີ່ທ່ານສຳເນົາແລ້ວ"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ວາງຮູບທີ່ທ່ານສຳເນົາແລ້ວ"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ວາງເນື້ອຫາທີ່ທ່ານສຳເນົາແລ້ວ"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"ກຳ​ລັງ​ກຽມ <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"ກຳລັງເປີດແອັບຯ."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"ກຳລັງສຳເລັດການເປີດລະບົບ."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"ປິດໜ້າຈໍໄວ້ບໍ?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"ໃນລະຫວ່າງການຕັ້ງຄ່າລາຍນິ້ວມືຂອງທ່ານ, ທ່ານກົດປຸ່ມເປີດປິດ.\n\nໂດຍປົກກະຕິນີ້ຈະເປັນການປິດໜ້າຈໍຂອງທ່ານ."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"ປິດໄວ້"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"ຍົກເລີກ"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກ"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Tap to return to game"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Choose game"</string>
@@ -1718,8 +1713,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ໃຊ້ປຸ່ມລັດ"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"ການປີ້ນສີ"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"ການແກ້ໄຂຄ່າສີ"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ໂໝດມືດຽວ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ຫຼຸດແສງເປັນພິເສດ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ເປີດໃຊ້ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ແລ້ວ."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ກົດປຸ່ມລະດັບສຽງຄ້າງໄວ້. ປິດ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ໄວ້ແລ້ວ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 4497d9a..75facc1 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1028,8 +1028,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Tekstas nukopijuotas į iškarpinę."</string>
     <string name="copied" msgid="4675902854553014676">"Nukopijuota"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"„<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>“ įklijuota iš „<xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>“"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"„<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>“ įklijuota iš iškarpinės"</string>
     <string name="pasted_text" msgid="4298871641549173733">"„<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>“ įklijavo jūsų nukopijuotą tekstą"</string>
     <string name="pasted_image" msgid="4729097394781491022">"„<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>“ įklijavo jūsų nukopijuotą vaizdą"</string>
     <string name="pasted_content" msgid="646276353060777131">"„<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>“ įklijavo jūsų nukopijuotą turinį"</string>
@@ -1300,14 +1299,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Ruošiama „<xliff:g id="APPNAME">%1$s</xliff:g>“."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Paleidžiamos programos."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Užbaigiamas paleidimas."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Išjungti ekraną?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Nustatydami kontrolinį kodą paspaudėte maitinimo mygtuką.\n\nĮprastai juo išjungiamas ekranas."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Išjungti"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Atšaukti"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Vykdoma „<xliff:g id="APP">%1$s</xliff:g>“"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Palieskite, kad grįžtumėte į žaidimą"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Pasirinkite žaidimą"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 618f8d6..876f522 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Текстот е копиран на таблата со исечоци."</string>
     <string name="copied" msgid="4675902854553014676">"Копирано"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> залепи од <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> залепи од вашата привремена меморија"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> го залепи текстот што го копиравте"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ја залепи сликата што ја копиравте"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ги залепи содржините што ги копиравте"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Се подготвува <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Се стартуваат апликациите."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Подигањето завршува."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Да се исклучи екранот?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Додека го поставувавте вашиот отпечаток, го притиснавте копчето за вклучување.\n\nОва обично го исклучува екранот."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Исклучи"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Откажи"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> работи"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Допрете за да се вратите во играта"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Избор на игра"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 5d411bd..ab08384 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -42,10 +42,10 @@
     <string name="serviceErased" msgid="997354043770513494">"Амжилттай арилгалаа."</string>
     <string name="passwordIncorrect" msgid="917087532676155877">"Буруу нууц үг"</string>
     <string name="mmiComplete" msgid="6341884570892520140">"MMI дууссан."</string>
-    <string name="badPin" msgid="888372071306274355">"Таны бичсэн хуучин PIN буруу байна."</string>
+    <string name="badPin" msgid="888372071306274355">"Таны бичсэн хуучин ПИН буруу байна."</string>
     <string name="badPuk" msgid="4232069163733147376">"Таны бичсэн PUК буруу байна."</string>
-    <string name="mismatchPin" msgid="2929611853228707473">"Таны оруулсан PIN таарахгүй байна."</string>
-    <string name="invalidPin" msgid="7542498253319440408">"4-8 тооноос бүтэх PIN-г бичнэ үү."</string>
+    <string name="mismatchPin" msgid="2929611853228707473">"Таны оруулсан ПИН таарахгүй байна."</string>
+    <string name="invalidPin" msgid="7542498253319440408">"4-8 тооноос бүтэх ПИН-г бичнэ үү."</string>
     <string name="invalidPuk" msgid="8831151490931907083">"8-с цөөнгүй тооноос бүтэх PUK-г бичнэ үү."</string>
     <string name="needPuk" msgid="7321876090152422918">"SIM картны PUK-түгжигдсэн. Тайлах бол PUK кодыг бичнэ үү."</string>
     <string name="needPuk2" msgid="7032612093451537186">"SIM картыг блокоос гаргах бол PUK2-г бичнэ үү."</string>
@@ -64,7 +64,7 @@
     <string name="CwMmi" msgid="3164609577675404761">"дуудлага хүлээлгэх"</string>
     <string name="BaMmi" msgid="7205614070543372167">"Дуудлага хориглох"</string>
     <string name="PwdMmi" msgid="3360991257288638281">"Нууц үг солих"</string>
-    <string name="PinMmi" msgid="7133542099618330959">"PIN солих"</string>
+    <string name="PinMmi" msgid="7133542099618330959">"ПИН солих"</string>
     <string name="CnipMmi" msgid="4897531155968151160">"Дуудсан дугаар харуулах"</string>
     <string name="CnirMmi" msgid="885292039284503036">"Дуудлага хийгчийн дугаар хязгаарлагдсан"</string>
     <string name="ThreeWCMmi" msgid="2436550866139999411">"Гурван чиглэлт дуудлага"</string>
@@ -866,14 +866,14 @@
     <string name="sipAddressTypeWork" msgid="7873967986701216770">"Ажлын"</string>
     <string name="sipAddressTypeOther" msgid="6317012577345187275">"Бусад"</string>
     <string name="quick_contacts_not_available" msgid="1262709196045052223">"Энэ харилцагчийг харах аппликейшн олдсонгүй."</string>
-    <string name="keyguard_password_enter_pin_code" msgid="6401406801060956153">"PIN кодыг бичнэ үү"</string>
-    <string name="keyguard_password_enter_puk_code" msgid="3112256684547584093">"PUK-г бичээд шинэ PIN код оруулна уу"</string>
+    <string name="keyguard_password_enter_pin_code" msgid="6401406801060956153">"ПИН кодыг бичнэ үү"</string>
+    <string name="keyguard_password_enter_puk_code" msgid="3112256684547584093">"PUK-г бичээд шинэ ПИН код оруулна уу"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="2825313071899938305">"PUK код"</string>
-    <string name="keyguard_password_enter_pin_prompt" msgid="5505434724229581207">"Шинэ PIN код"</string>
+    <string name="keyguard_password_enter_pin_prompt" msgid="5505434724229581207">"Шинэ ПИН код"</string>
     <string name="keyguard_password_entry_touch_hint" msgid="4032288032993261520"><font size="17">"Нууц үг шивэх бол товшино уу"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="2751130557661643482">"Тайлах нууц үгийг бичнэ үү"</string>
-    <string name="keyguard_password_enter_pin_password_code" msgid="7792964196473964340">"Тайлах PIN-г оруулна уу"</string>
-    <string name="keyguard_password_wrong_pin_code" msgid="8583732939138432793">"Буруу PIN код."</string>
+    <string name="keyguard_password_enter_pin_password_code" msgid="7792964196473964340">"Тайлах ПИН-г оруулна уу"</string>
+    <string name="keyguard_password_wrong_pin_code" msgid="8583732939138432793">"Буруу ПИН код."</string>
     <string name="keyguard_label_text" msgid="3841953694564168384">"Тайлах бол Цэсийг дараад 0."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"Яаралтай тусламжийн дугаар"</string>
     <string name="lockscreen_carrier_default" msgid="6192313772955399160">"Үйлчилгээ байхгүй"</string>
@@ -911,7 +911,7 @@
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"SIM картны түгжээг гаргаж байна…"</string>
     <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"Та нууц үгээ <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
-    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"Та PIN кодоо <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+    <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"Та ПИН кодоо <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та таблетаа тайлахын тулд Google нэвтрэлтээ ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурсан байна. Та дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсан тохиолдолд Android TV төхөөрөмжийнхөө түгжээг тайлахын тулд Google-д нэвтрэх шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оролдвол, та таблетаа тайлахын тулд Google нэвтрэлтээ ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Текст хуулагдав."</string>
     <string name="copied" msgid="4675902854553014676">"Хуулсан"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>-с буулгасан <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Таны түр санах ойгоос <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>-г буулгасан"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> таны хуулсан текстийг буулгасан"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> таны хуулсан зургийг буулгасан"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> таны хуулсан контентыг буулгасан"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Бэлдэж байна <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Апп-г эхлүүлж байна."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Эхлэлийг дуусгаж байна."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Дэлгэцийг унтраах уу?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Та хурууны хээгээ тохируулж байх үед Асаах/унтраах товчийг дарсан байна.\n\nЭнэ нь ихэвчлэн таны дэлгэцийг унтраана."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Унтраах"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Цуцлах"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> ажиллаж байна"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Тоглоом руу буцахын тулд товших"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Тоглоом сонгох"</string>
@@ -1647,24 +1642,24 @@
     <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"Хээг мартсан"</string>
     <string name="kg_wrong_pattern" msgid="1342812634464179931">"Буруу хээ"</string>
     <string name="kg_wrong_password" msgid="2384677900494439426">"Нууц үг буруу"</string>
-    <string name="kg_wrong_pin" msgid="3680925703673166482">"PIN буруу"</string>
+    <string name="kg_wrong_pin" msgid="3680925703673166482">"ПИН буруу"</string>
     <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568">
       <item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> секундын дараа дахин оролдоно уу.</item>
       <item quantity="one">1 секундын дараа дахин оролдоно уу.</item>
     </plurals>
     <string name="kg_pattern_instructions" msgid="8366024510502517748">"Хээг зурах"</string>
-    <string name="kg_sim_pin_instructions" msgid="6479401489471690359">"SIM PIN оруулна уу"</string>
-    <string name="kg_pin_instructions" msgid="7355933174673539021">"PIN оруулна уу"</string>
+    <string name="kg_sim_pin_instructions" msgid="6479401489471690359">"SIM ПИН оруулна уу"</string>
+    <string name="kg_pin_instructions" msgid="7355933174673539021">"ПИН оруулна уу"</string>
     <string name="kg_password_instructions" msgid="7179782578809398050">"Нууц үгээ оруулна уу"</string>
     <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"SIM идэвхгүй байна. Үргэлжлүүлэх бол PUK кодыг оруулна уу. Дэлгэрэнгүй мэдээллийг оператороос асууна ууу"</string>
-    <string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Хүссэн PIN кодоо оруулна уу"</string>
-    <string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Хүссэн PIN кодоо дахин оруулна уу"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Хүссэн ПИН кодоо оруулна уу"</string>
+    <string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Хүссэн ПИН кодоо дахин оруулна уу"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"SIM картны түгжээг гаргаж байна…"</string>
-    <string name="kg_password_wrong_pin_code" msgid="9013856346870572451">"Буруу PIN код."</string>
-    <string name="kg_invalid_sim_pin_hint" msgid="4821601451222564077">"4-8 тооноос бүтэх PIN-г бичнэ үү."</string>
+    <string name="kg_password_wrong_pin_code" msgid="9013856346870572451">"Буруу ПИН код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="4821601451222564077">"4-8 тооноос бүтэх ПИН-г бичнэ үү."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"PUK код 8 тоотой байх ёстой."</string>
     <string name="kg_invalid_puk" msgid="4809502818518963344">"Зөв PUK кодыг дахин оруулна уу. Давтан оролдвол SIM нь бүрмөсөн идэвхгүй болгоно."</string>
-    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"PIN кодууд таарахгүй байна"</string>
+    <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"ПИН кодууд таарахгүй байна"</string>
     <string name="kg_login_too_many_attempts" msgid="699292728290654121">"Хээ оруулах оролдлого хэт олон"</string>
     <string name="kg_login_instructions" msgid="3619844310339066827">"Түгжээг тайлах бол Google акаунтаараа нэвтэрнэ үү."</string>
     <string name="kg_login_username_hint" msgid="1765453775467133251">"Хэрэглэгчийн нэр (имэйл)"</string>
@@ -1673,8 +1668,8 @@
     <string name="kg_login_invalid_input" msgid="8292367491901220210">"Хэрэглэгчийн нэр эсвэл нууц үг буруу."</string>
     <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Хэрэглэгчийн нэр нууц үгээ мартсан уу?\n"<b>"google.com/accounts/recovery"</b>"-д зочилно уу."</string>
     <string name="kg_login_checking_password" msgid="4676010303243317253">"Бүртгэл шалгаж байна…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"Та PIN кодоо <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"Та PIN кодоо <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"Та ПИН кодоо <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"Та ПИН кодоо <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"Та таблетыг тайлах гэж <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу оролдлоо. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оролдвол таблет үйлдвэрийн үндсэн утгаараа тохируулагдах ба хэрэглэгчийн дата бүхэлдээ устана."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"Та Android TV төхөөрөмжийнхөө түгжээг тайлахаар <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу оролдсон байна. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаагийн амжилтгүй оролдлогын дараагаас таны Android TV төхөөрөмжийг үйлдвэрийн өгөгдмөл төлөвт шинэчлэх бөгөөд хэрэглэгчийн бүх өгөгдөл устах болно."</string>
@@ -1841,14 +1836,14 @@
     <string name="print_service_installed_title" msgid="6134880817336942482">"<xliff:g id="NAME">%s</xliff:g> үйлчилгээ суугдсан"</string>
     <string name="print_service_installed_message" msgid="7005672469916968131">"Идэвхжүүлэх бол товшино уу"</string>
     <string name="restr_pin_enter_admin_pin" msgid="1199419462726962697">"Админы ПИН-г оруулах"</string>
-    <string name="restr_pin_enter_pin" msgid="373139384161304555">"PIN оруулна уу"</string>
+    <string name="restr_pin_enter_pin" msgid="373139384161304555">"ПИН оруулна уу"</string>
     <string name="restr_pin_incorrect" msgid="3861383632940852496">"Буруу"</string>
-    <string name="restr_pin_enter_old_pin" msgid="7537079094090650967">"Одоогийн PIN"</string>
-    <string name="restr_pin_enter_new_pin" msgid="3267614461844565431">"Шинэ PIN"</string>
-    <string name="restr_pin_confirm_pin" msgid="7143161971614944989">"Шинэ PIN-г баталгаажуулах"</string>
-    <string name="restr_pin_create_pin" msgid="917067613896366033">"Өөрчлөлтийг хязгаарлахад зориулан PIN үүсгэх"</string>
-    <string name="restr_pin_error_doesnt_match" msgid="7063392698489280556">"PIN таарахгүй байна. Дахин оролдоно уу."</string>
-    <string name="restr_pin_error_too_short" msgid="1547007808237941065">"PIN хэт богино байна. Хамгийн багадаа 4 цифртэй байх ёстой."</string>
+    <string name="restr_pin_enter_old_pin" msgid="7537079094090650967">"Одоогийн ПИН"</string>
+    <string name="restr_pin_enter_new_pin" msgid="3267614461844565431">"Шинэ ПИН"</string>
+    <string name="restr_pin_confirm_pin" msgid="7143161971614944989">"Шинэ ПИН-г баталгаажуулах"</string>
+    <string name="restr_pin_create_pin" msgid="917067613896366033">"Өөрчлөлтийг хязгаарлахад зориулан ПИН үүсгэх"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="7063392698489280556">"ПИН таарахгүй байна. Дахин оролдоно уу."</string>
+    <string name="restr_pin_error_too_short" msgid="1547007808237941065">"ПИН хэт богино байна. Хамгийн багадаа 4 цифртэй байх ёстой."</string>
     <plurals name="restr_pin_countdown" formatted="false" msgid="4427486903285216153">
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> секундын дараа дахин оролдоно уу</item>
       <item quantity="one">1 секундын дараа дахин оролдоно уу</item>
@@ -1868,7 +1863,7 @@
     <string name="managed_profile_label_badge" msgid="6762559569999499495">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
-    <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Бэхэлснийг болиулахаасаа өмнө PIN асуух"</string>
+    <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Бэхэлснийг болиулахаасаа өмнө ПИН асуух"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Бэхэлснийг болиулахаас өмнө түгжээ тайлах хээ асуух"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
     <string name="package_installed_device_owner" msgid="7035926868974878525">"Таны админ суулгасан"</string>
@@ -1997,7 +1992,7 @@
     <string name="profile_encrypted_message" msgid="1128512616293157802">"Ажлын профайлын түгжээг тайлахын тулд дарна уу"</string>
     <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"<xliff:g id="PRODUCT_NAME">%1$s</xliff:g>-д холбогдсон"</string>
     <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Файлыг үзэхийн тулд дарна уу"</string>
-    <string name="pin_target" msgid="8036028973110156895">"PIN"</string>
+    <string name="pin_target" msgid="8036028973110156895">"ПИН"</string>
     <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g>-г бэхлэх"</string>
     <string name="unpin_target" msgid="3963318576590204447">"Unpin"</string>
     <string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g>-г тогтоосныг болиулах"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index f937404..d154582 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Gunakan Pintasan"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Penyongsangan Warna"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Pembetulan Warna"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mod sebelah tangan"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Amat malap"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dihidupkan."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Kekunci kelantangan ditahan. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> dimatikan."</string>
@@ -1875,10 +1874,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Dikemas kini oleh pentadbir anda"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dipadamkan oleh pentadbir anda"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual, ciri tertentu dan sesetengah sambungan rangkaian.\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual, ciri tertentu dan sesetengah sambungan rangkaian."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu penggunaan data dikurangkan, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Hidupkan Penjimat Data?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Hidupkan"</string>
@@ -1981,10 +1978,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tidak tersedia sekarang. Ini diurus oleh <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"Ketahui lebih lanjut"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Nyahjeda apl"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"Hidupkan apl kerja?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Dapatkan akses kepada apl kerja dan pemberitahuan anda"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Hidupkan"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Apl tidak tersedia"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia sekarang."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index e7f5ea0..2054e47 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ဖြတ်လမ်းလင့်ခ်ကို သုံးရန်"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"အရောင် ပြောင်းပြန်လှန်ခြင်း"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"အရောင်ပြင်ဆင်ခြင်း"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"လက်တစ်ဖက်သုံးမုဒ်"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ပိုမှိန်ခြင်း"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ဖွင့်လိုက်သည်။"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"အသံခလုတ်များကို ဖိထားသည်။ <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ပိတ်လိုက်သည်။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index fd96a2a..a6f945c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Kopierte tekst til utklippstavlen."</string>
     <string name="copied" msgid="4675902854553014676">"Kopiert"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> limte inn fra <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> har limt inn fra utklippstavlen"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> limte inn tekst du kopierte"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> limte inn et bilde du kopierte"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> limte inn innhold du kopierte"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Forbereder <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Starter apper."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Ferdigstiller oppstart."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Vil du slå av skjermen?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Da du konfigurerte fingeravtrykket, trykket du på av/på-knappen.\n\nDette slår vanligvis av skjermen."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Slå av"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Avbryt"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> kjører"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Trykk for å gå tilbake til spillet"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Velg et spill"</string>
@@ -1718,8 +1713,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Bruk snarveien"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Fargeinvertering"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Fargekorrigering"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhåndsmodus"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dimmet"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått på."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumtastene holdes inne. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> er slått av."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b7fc042..37ffd46 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Tekst naar klembord gekopieerd."</string>
     <string name="copied" msgid="4675902854553014676">"Gekopieerd"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> geplakt vanuit <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> heeft geplakt vanaf het klembord"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> heeft door jou gekopieerde tekst geplakt"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> heeft een door jou gekopieerde afbeelding geplakt"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> heeft door jou gekopieerde content geplakt"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> voorbereiden."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Apps starten."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Opstarten afronden."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Scherm uitzetten?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Toen je je vingerafdruk instelde, heb je op de aan/uit-knop gedrukt.\n\nDaarmee wordt het scherm meestal uitgezet."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Uitzetten"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Annuleren"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Tik om terug te keren naar de game"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Game kiezen"</string>
@@ -1718,8 +1713,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Sneltoets gebruiken"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Kleurinversie"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Kleurcorrectie"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Bediening met één hand"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra gedimd"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> staat aan."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Volumetoetsen ingedrukt gehouden. <xliff:g id="SERVICE_NAME">%1$s</xliff:g> staat uit."</string>
@@ -1875,10 +1869,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Geüpdatet door je beheerder"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Verwijderd door je beheerder"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, bepaalde visuele effecten, bepaalde functies en sommige netwerkverbindingen beperkt of uitgezet.\n\n"<annotation id="url">"Meer informatie"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, bepaalde visuele effecten, bepaalde functies en sommige netwerkverbindingen beperkt of uitgezet."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens sturen of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Databesparing aanzetten?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Aanzetten"</string>
@@ -1981,10 +1973,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> is nu niet beschikbaar. Dit wordt beheerd door <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"Meer info"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"App niet meer onderbreken"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"Werk-apps aanzetten?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Krijg toegang tot je werk-apps en meldingen"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Aanzetten"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 4574847..15a0531 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"ଟେକ୍ସଟ୍‍ କ୍ଲିପବୋର୍ଡକୁ କପୀ ହୋଇଯାଇଛି"</string>
     <string name="copied" msgid="4675902854553014676">"କପି କରାଗଲା"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>ରୁ ପେଷ୍ଟ କରିଛି"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କ କ୍ଲିପବୋର୍ଡରୁ ପେଷ୍ଟ କରିଛି"</string>
     <string name="pasted_text" msgid="4298871641549173733">"ଆପଣ କପି କରିଥିବା ଟେକ୍ସଟକୁ <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ପେଷ୍ଟ କରିଛି"</string>
     <string name="pasted_image" msgid="4729097394781491022">"ଆପଣ କପି କରିଥିବା ଏକ ଛବିକୁ <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ପେଷ୍ଟ କରିଛି"</string>
     <string name="pasted_content" msgid="646276353060777131">"ଆପଣ କପି କରିଥିବା ବିଷୟବସ୍ତୁକୁ <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ପେଷ୍ଟ କରିଛି"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> ପ୍ରସ୍ତୁତ କରାଯାଉଛି।"</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"ଆପ୍‍ ଆରମ୍ଭ କରାଯାଉଛି।"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"ବୁଟ୍‍ ସମାପ୍ତ କରୁଛି।"</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"ସ୍କ୍ରିନ୍ ବନ୍ଦ କରିବେ?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"ଆପଣଙ୍କ ଟିପଚିହ୍ନ ସେଟ୍ ଅପ୍ କରିବା ସମୟରେ, ଆପଣ ପାୱାର ବଟନ୍ ଦବାଇଛନ୍ତି।\n\nଏହା ସାଧାରଣତଃ ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ ବନ୍ଦ କରେ।"</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"ବନ୍ଦ କରନ୍ତୁ"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"ବାତିଲ୍ କରନ୍ତୁ"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> ଚାଲୁଛି"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"ଗେମ୍‌କୁ ଫେରିଆସିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"ଗେମ୍ ଚୟନ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 72fe314..50e1f98 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ਸ਼ਾਰਟਕੱਟ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"ਰੰਗ ਪਲਟਨਾ"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"ਰੰਗ ਸੁਧਾਈ"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ਇੱਕ ਹੱਥ ਮੋਡ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਦਬਾ ਕੇ ਰੱਖੀਆਂ ਗਈਆਂ। <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index c7f35d5..b77be3d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1028,8 +1028,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Tekst został skopiowany do schowka."</string>
     <string name="copied" msgid="4675902854553014676">"Skopiowano"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Aplikacja <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> wkleiła dane z aplikacji <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Aplikacja <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> skopiowała dane ze schowka"</string>
     <string name="pasted_text" msgid="4298871641549173733">"Aplikacja <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> wkleiła skopiowany tekst"</string>
     <string name="pasted_image" msgid="4729097394781491022">"Aplikacja <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> wkleiła skopiowany obraz"</string>
     <string name="pasted_content" msgid="646276353060777131">"Aplikacja <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> wkleiła skopiowane treści"</string>
@@ -1300,14 +1299,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Przygotowuję aplikację <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Uruchamianie aplikacji."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Kończenie uruchamiania."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Wyłączyć ekran?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Podczas konfigurowania odcisku palca naciśnięto przycisk zasilania.\n\nZwykle powoduje to wyłączenie ekranu."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Wyłącz"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Anuluj"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Działa <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Kliknij, by wrócić do gry"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Wybierz grę"</string>
@@ -1762,8 +1757,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"Użyj skrótu"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"Odwrócenie kolorów"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"Korekcja kolorów"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Tryb jednej ręki"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatkowe przyciemnienie"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została włączona."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"Przytrzymano klawisze głośności. Usługa <xliff:g id="SERVICE_NAME">%1$s</xliff:g> została wyłączona."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index e5e9be4..bc0342a 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Texto copiado para a área de transferência."</string>
     <string name="copied" msgid="4675902854553014676">"Copiado"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Dados do app <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> colados no app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou conteúdo da sua área de transferência"</string>
     <string name="pasted_text" msgid="4298871641549173733">"O app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou o texto copiado"</string>
     <string name="pasted_image" msgid="4729097394781491022">"O app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou uma imagem copiada"</string>
     <string name="pasted_content" msgid="646276353060777131">"O app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou o conteúdo copiado"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Iniciando apps."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Concluindo a inicialização."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Desligar a tela?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Durante a configuração da sua impressão digital, você pressionou o botão liga/desliga.\n\nNormalmente, essa ação desliga a tela."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Desligar"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Cancelar"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Toque para voltar ao jogo"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Escolha o jogo"</string>
@@ -1874,10 +1869,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede.\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
@@ -1980,10 +1973,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível no momento. Isso é gerenciado pelo app <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Retomar app"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"Ativar apps de trabalho?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Acesse seus apps e notificações de trabalho"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index cb00dce..db561c9 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Texto copiado para a área de transferência."</string>
     <string name="copied" msgid="4675902854553014676">"Copiado"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"A app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou da app <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou a partir da área de transferência"</string>
     <string name="pasted_text" msgid="4298871641549173733">"A app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou o texto que copiou"</string>
     <string name="pasted_image" msgid="4729097394781491022">"A app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou uma imagem que copiou"</string>
     <string name="pasted_content" msgid="646276353060777131">"A app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou o conteúdo que copiou"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"A preparar o <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"A iniciar aplicações"</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"A concluir o arranque."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Pretende desligar o ecrã?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Quando configurou a sua impressão digital, premiu o botão ligar/desligar.\n\nGeralmente, esta ação desativa o seu ecrã."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Desligar"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Cancelar"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Toque para regressar ao jogo."</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Selecionar jogo"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index e5e9be4..bc0342a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Texto copiado para a área de transferência."</string>
     <string name="copied" msgid="4675902854553014676">"Copiado"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Dados do app <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> colados no app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou conteúdo da sua área de transferência"</string>
     <string name="pasted_text" msgid="4298871641549173733">"O app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou o texto copiado"</string>
     <string name="pasted_image" msgid="4729097394781491022">"O app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou uma imagem copiada"</string>
     <string name="pasted_content" msgid="646276353060777131">"O app <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> colou o conteúdo copiado"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Preparando <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Iniciando apps."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Concluindo a inicialização."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Desligar a tela?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Durante a configuração da sua impressão digital, você pressionou o botão liga/desliga.\n\nNormalmente, essa ação desliga a tela."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Desligar"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Cancelar"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Toque para voltar ao jogo"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Escolha o jogo"</string>
@@ -1874,10 +1869,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede.\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
@@ -1980,10 +1973,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível no momento. Isso é gerenciado pelo app <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Retomar app"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"Ativar apps de trabalho?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Acesse seus apps e notificações de trabalho"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"O app não está disponível"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível no momento."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index cd2561a..5d38e46 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"පෙළ පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
     <string name="copied" msgid="4675902854553014676">"පිටපත් කළා"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g> වෙතින් අලවන ලදි"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"ඔබගේ පසුරු පුවරුව වෙතින් <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> පිටපත් කරන ලදි"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ඔබ පිටපත් කළ පෙළ ඇලවීය"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ඔබ පිටපත් කළ රූපයක් ඇලවීය"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ඔබ පිටපත් කළ අන්තර්ගතය ඇලවීය"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> සූදානම් කරමින්."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"යෙදුම් ආරම්භ කරමින්."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"ඇරඹුම අවසාන කරමින්."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"තිරය ක්‍රියාවිරහිත කරන්නද?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"ඔබගේ ඇඟිලි සලකුණ පිහිටුවන අතරතුර ඔබ බල බොත්තම එබුවේය.\n\nමෙය සාමාන්‍යයෙන් ඔබගේ තිරය ක්‍රියාවිරහිත කරයි."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"ක්‍රියාවිරහිත කරන්න"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"අවලංගු කරන්න"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> ධාවනය වෙමින්"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"ක්‍රීඩාව වෙත ආපසු යාමට තට්ටු කරන්න"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"ක්‍රීඩාව තෝරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 90f4f06..ac5483a 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1028,8 +1028,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Text bol skopírovaný do schránky."</string>
     <string name="copied" msgid="4675902854553014676">"Skopírované"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Aplikácia <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> prilepila údaje z aplikácie <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Aplikácia <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> bola prilepená zo schránky"</string>
     <string name="pasted_text" msgid="4298871641549173733">"Aplikácia <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> prilepila text, ktorý ste skopírovali"</string>
     <string name="pasted_image" msgid="4729097394781491022">"Aplik. <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> prilepila obrázok, ktorý ste skopírovali"</string>
     <string name="pasted_content" msgid="646276353060777131">"Aplikácia <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> prilepila obsah, ktorý ste skopírovali"</string>
@@ -1300,14 +1299,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Pripravuje sa aplikácia <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Prebieha spúšťanie aplikácií."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Prebieha dokončovanie spúšťania."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Chcete vypnúť obrazovku?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Pri nastavovaní odtlačku prsta ste stlačili vypínač.\n\nObrazovka sa tým zvyčajne vypne."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Vypnúť"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Zrušiť"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Spustená aplikácia: <xliff:g id="APP">%1$s</xliff:g>"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Klepnutím prejdete späť do hry"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Vyberte hru"</string>
@@ -1921,10 +1916,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty, určité funkcie a niektoré pripojenia k sieti.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty, určité funkcie a niektoré pripojenia k sieti."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Môže to napríklad znamenať, že sa obrázky zobrazia, až keď na ne klepnete."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnúť šetrič dát?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnúť"</string>
@@ -2045,10 +2038,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikácia <xliff:g id="APP_NAME_0">%1$s</xliff:g> nie je momentálne k dispozícii. Spravuje to aplikácia <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"Ďalšie informácie"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Znova spustiť aplikáciu"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"Zapnúť pracovné aplikácie?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Získajte prístup k svojim pracovným aplikáciám a upozorneniam"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnúť"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplikácia nie je dostupná"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> nie je teraz dostupná."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index f9dff5f..d895f74 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Teksti u kopjua në kujtesën e fragmenteve."</string>
     <string name="copied" msgid="4675902854553014676">"U kopjua"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> u ngjit nga <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ngjitur nga kujtesa jote e fragmenteve"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ngjiti një tekst që kopjove"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ngjiti një imazh që kopjove"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> ngjiti një përmbajtje që kopjove"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Po përgatit <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Aplikacionet e fillimit."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Po përfundon nisjen."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Të fiket ekrani?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Gjatë konfigurimit të gjurmës së gishtit tënd, ke shtypur butonin e \"Energjisë\".\n\nKjo zakonisht fik ekranin tënd."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Fik"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Anulo"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> është në punë"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Trokit për t\'u kthyer te loja"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Zgjidh një lojë"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index ee7cbb7..3512945 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1025,8 +1025,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Текст је копиран у привремену меморију."</string>
     <string name="copied" msgid="4675902854553014676">"Копирано је"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"Апликација<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> је налепила податке из апликације <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"Садржај апликације <xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> је налепљен у привр. меморију"</string>
     <string name="pasted_text" msgid="4298871641549173733">"Апликација<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> је налепила текст који сте копирали"</string>
     <string name="pasted_image" msgid="4729097394781491022">"Апликација<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> је налепила слику коју сте копирали"</string>
     <string name="pasted_content" msgid="646276353060777131">"Апликација<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> је налепила садржај који сте копирали"</string>
@@ -1280,14 +1279,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Припрема се <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Покретање апликација."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Завршавање покретања."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Желите да искључите екран?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Притисли сте дугме за укључивање током подешавања отиска прста.\n\nТако се најчешће искључује екран."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Искључи"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Откажи"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Додирните да бисте се вратили у игру"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Одаберите игру"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 05aa23e..71fcb7d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1022,8 +1022,7 @@
     <string name="text_copied" msgid="2531420577879738860">"Text har kopierats till urklipp."</string>
     <string name="copied" msgid="4675902854553014676">"Kopierat"</string>
     <string name="pasted_from_app" msgid="5627698450808256545">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> klistrade in från <xliff:g id="SOURCE_APP_NAME">%2$s</xliff:g>"</string>
-    <!-- no translation found for pasted_from_clipboard (7355790625710831847) -->
-    <skip />
+    <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> klistrade in från urklipp"</string>
     <string name="pasted_text" msgid="4298871641549173733">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> klistrade in text som du kopierade"</string>
     <string name="pasted_image" msgid="4729097394781491022">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> klistrade in en bild som du kopierade"</string>
     <string name="pasted_content" msgid="646276353060777131">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> klistrade in innehåll som du kopierade"</string>
@@ -1260,14 +1259,10 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> förbereds."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Appar startas."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Uppgraderingen är klar."</string>
-    <!-- no translation found for fp_enrollment_powerbutton_intent_title (3385634173366119903) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_message (6582149052513682522) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_positive_button (5963520983910436791) -->
-    <skip />
-    <!-- no translation found for fp_enrollment_powerbutton_intent_negative_button (6465764183480190748) -->
-    <skip />
+    <string name="fp_enrollment_powerbutton_intent_title" msgid="3385634173366119903">"Vill du stänga av skärmen?"</string>
+    <string name="fp_enrollment_powerbutton_intent_message" msgid="6582149052513682522">"Du tryckte på strömbrytaren när du skulle konfigurera fingeravtrycket.\n\nDet brukar leda till att skärmen stängs av."</string>
+    <string name="fp_enrollment_powerbutton_intent_positive_button" msgid="5963520983910436791">"Stäng av"</string>
+    <string name="fp_enrollment_powerbutton_intent_negative_button" msgid="6465764183480190748">"Avbryt"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> körs"</string>
     <string name="heavy_weight_notification_detail" msgid="6802247239468404078">"Återgå till spelet genom att trycka här"</string>
     <string name="heavy_weight_switcher_title" msgid="3861984210040100886">"Välj spel"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 8df5d3a..663fc84 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ใช้ทางลัด"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"การกลับสี"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"การแก้สี"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"โหมดมือเดียว"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"หรี่แสงเพิ่มเติม"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว เปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"กดปุ่มปรับระดับเสียงค้างไว้แล้ว ปิด <xliff:g id="SERVICE_NAME">%1$s</xliff:g> แล้ว"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 69a3c06..50324d8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用快捷方式"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"颜色反转"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"单手模式"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"极暗"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已开启。"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量键。<xliff:g id="SERVICE_NAME">%1$s</xliff:g>已关闭。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 19408c2..a45f981 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1718,8 +1718,7 @@
     <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"使用捷徑"</string>
     <string name="color_inversion_feature_name" msgid="326050048927789012">"色彩反轉"</string>
     <string name="color_correction_feature_name" msgid="3655077237805422597">"色彩校正"</string>
-    <!-- no translation found for one_handed_mode_feature_name (2334330034828094891) -->
-    <skip />
+    <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"單手模式"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"超暗"</string>
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已開啟。"</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"已按住音量鍵。「<xliff:g id="SERVICE_NAME">%1$s</xliff:g>」已關閉。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 67da660..b983f11 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1875,10 +1875,8 @@
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Kubuyekezwe umlawuli wakho"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Kususwe umlawuli wakho"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"KULUNGILE"</string>
-    <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
-    <skip />
-    <!-- no translation found for battery_saver_description (8518809702138617167) -->
-    <skip />
+    <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"Isilondolozi Sebhethri sivula itimu emnyama futhi sikhawulele noma sivale umsebenzi ongemuva, imiphumela ethile yokubuka, izakhi ezithile, nokuxhumeka kwenethiwekhi ethile.\n\n"<annotation id="url">"Funda kabanzi"</annotation></string>
+    <string name="battery_saver_description" msgid="8518809702138617167">"Isilondolozi Sebhethri sivula ingqikithi emnyama futhi sibeke umkhawulo noma sivale umsebenzi ongemuva, imiphumela ethile yokubuka, izici ezithile, nokuxhumeka okuthile kwenethiwekhi."</string>
     <string name="data_saver_description" msgid="4995164271550590517">"Ukusiza ukwehlisa ukusetshenziswa kwedatha, iseva yedatha igwema ezinye izinhlelo zokusebenza ukuthi zithumele noma zamukele idatha ngasemuva. Uhlelo lokusebenza olisebenzisa okwamanje lingafinyelela idatha, kodwa lingenza kanjalo kancane. Lokhu kungachaza, isibonelo, ukuthi izithombe azibonisi uze uzithephe."</string>
     <string name="data_saver_enable_title" msgid="7080620065745260137">"Vula iseva yedatha?"</string>
     <string name="data_saver_enable_button" msgid="4399405762586419726">"Vula"</string>
@@ -1981,10 +1979,8 @@
     <string name="app_suspended_default_message" msgid="6451215678552004172">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> ayitholakali okwamanje. Lokhu kuphethwe i-<xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
     <string name="app_suspended_more_details" msgid="211260942831587014">"Funda kabanzi"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Susa ukuphumuza uhlelo lokusebenza"</string>
-    <!-- no translation found for work_mode_off_title (961171256005852058) -->
-    <skip />
-    <!-- no translation found for work_mode_off_message (7319580997683623309) -->
-    <skip />
+    <string name="work_mode_off_title" msgid="961171256005852058">"Vula ama-app okusebenza womsebenzi?"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Thola ukufinyelela kuma-app akho womsebenzi kanye nezaziso"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Vula"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c5f4fd1..6386274 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1954,6 +1954,13 @@
          See the <a href="{@docRoot}about/versions/12/backup-restore">Changes in backup and restore</a>
          document for the format of the XML file.-->
         <attr name="dataExtractionRules" format="reference"/>
+
+        <!-- @hide Request exemption from the foreground service restrictions introduced in S
+        (https://developer.android.com/about/versions/12/foreground-services)
+        Note the framework <b>ignores</b> this attribute at this time. Once apps target S or above,
+        there's no way to be exempted (without using a privileged permission).
+        -->
+        <attr name="requestForegroundServiceExemption" format="boolean" />
     </declare-styleable>
 
     <!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 4f90a17..d334306 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -224,14 +224,14 @@
     <!-- The margin on the end of the top-line content views (accommodates the expander) -->
     <dimen name="notification_heading_margin_end">56dp</dimen>
 
-    <!-- The height of the notification action list -->
+    <!-- The total height of the notification action list -->
     <dimen name="notification_action_list_height">60dp</dimen>
 
     <!-- The margin of the notification action list at the top -->
     <dimen name="notification_action_list_margin_top">0dp</dimen>
 
-    <!-- The height of the notification action list -->
-    <dimen name="notification_action_emphasized_height">48dp</dimen>
+    <!-- The visual height of the emphasized notification action -->
+    <dimen name="notification_action_emphasized_height">36dp</dimen>
 
     <!-- The padding of the actions in non-conversation layout. For conversations, the analogous
          value is calculated in ConversationLayout#updateActionListPadding() -->
@@ -252,7 +252,7 @@
     <dimen name="notification_actions_icon_drawable_size">20dp</dimen>
 
     <!-- The corner radius if the emphasized action buttons in a notification -->
-    <dimen name="notification_action_button_radius">8dp</dimen>
+    <dimen name="notification_action_button_radius">18dp</dimen>
 
     <!-- Size of the stroke with for the emphasized notification button style -->
     <dimen name="emphasized_button_stroke_width">1dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 500a9da..f7a9930 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3099,6 +3099,8 @@
     <public name="durationBetweenRequestsMillis" />
     <public name="showInInputMethodPicker" />
     <public name="effectColor" />
+    <!-- @hide @TestApi -->
+    <public name="requestForegroundServiceExemption" />
   </staging-public-group>
 
   <staging-public-group type="drawable" first-id="0x010800b5">
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/Android.bp b/core/tests/batterystatstests/BatteryStatsViewer/Android.bp
index abac56b..6046a76 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/Android.bp
+++ b/core/tests/batterystatstests/BatteryStatsViewer/Android.bp
@@ -15,6 +15,7 @@
         "androidx.appcompat_appcompat",
         "androidx.cardview_cardview",
         "androidx.recyclerview_recyclerview",
+        "androidx.swiperefreshlayout_swiperefreshlayout",
         "com.google.android.material_material",
     ],
     platform_apis: true,
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_sum_24.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_sum_24.xml
new file mode 100644
index 0000000..3d29102
--- /dev/null
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/drawable/gm_sum_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="#d14d2c">
+<path
+      android:fillColor="@android:color/white"
+      android:pathData="M19,4H5v2l6,6 -6,6v2h14v-3h-9l5,-5 -5,-5h9V4z"/>
+</vector>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
index 98fc581..be0e135 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_entry_layout.xml
@@ -30,7 +30,8 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:layout_marginEnd="8dp"/>
+        android:layout_marginEnd="8dp"
+        android:paddingBottom="8dp"/>
 
     <TextView
         android:id="@+id/title"
@@ -40,7 +41,7 @@
         android:textAppearance="@style/TextAppearanceBody"/>
 
     <TextView
-        android:id="@+id/amount"
+        android:id="@+id/value1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginStart="8dp"
@@ -49,7 +50,7 @@
         android:textAppearance="@style/TextAppearanceBody"/>
 
     <TextView
-        android:id="@+id/percent"
+        android:id="@+id/value2"
         android:layout_width="76dp"
         android:layout_height="wrap_content"
         android:gravity="right"
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_activity_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_activity_layout.xml
deleted file mode 100644
index ecc89f0..0000000
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_activity_layout.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-  ~ Copyright (C) 2020 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-
-    <com.google.android.material.tabs.TabLayout
-        android:id="@+id/tab_layout"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
-
-    <androidx.viewpager.widget.ViewPager
-        android:id="@+id/pager"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
-
-</LinearLayout>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml
index bea38c1..f35a210 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_consumer_picker_layout.xml
@@ -14,22 +14,15 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<FrameLayout
+<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/swipe_refresh"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
     <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/list_view"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="gone"/>
+        android:layout_height="match_parent"/>
 
-    <ProgressBar
-        style="?android:attr/progressBarStyleLarge"
-        android:id="@+id/loading_view"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:indeterminate="true"/>
-</FrameLayout>
\ No newline at end of file
+</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
index 24d193c4..cf50d2a 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/res/layout/battery_stats_viewer_layout.xml
@@ -14,94 +14,89 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<FrameLayout
+<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/swipe_refresh"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
+
     <LinearLayout
         android:orientation="vertical"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
-        <androidx.cardview.widget.CardView
-            style="@style/LoadTestCardView"
+        <LinearLayout
             android:id="@+id/app_card"
+            android:orientation="vertical"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="10dp"
-            android:layout_marginEnd="10dp"
-            android:layout_marginBottom="10dp"
-            android:layout_marginStart="10dp"
-            android:padding="20dp">
+            android:visibility="invisible">
 
-            <LinearLayout
+            <androidx.cardview.widget.CardView
+                style="@style/LoadTestCardView"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:orientation="vertical"
-                android:minHeight="80dp"
-                android:paddingStart="10dp"
-                android:paddingEnd="10dp">
+                android:layout_marginTop="10dp"
+                android:layout_marginEnd="10dp"
+                android:layout_marginBottom="10dp"
+                android:layout_marginStart="10dp"
+                android:padding="20dp">
 
-                <include layout="@layout/battery_consumer_info_layout"/>
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="vertical"
+                    android:minHeight="80dp"
+                    android:paddingStart="10dp"
+                    android:paddingEnd="10dp">
+
+                    <include layout="@layout/battery_consumer_info_layout"/>
+                </LinearLayout>
+
+            </androidx.cardview.widget.CardView>
+
+            <LinearLayout
+                android:id="@+id/headings"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingTop="2dp"
+                android:paddingBottom="4dp">
+                <FrameLayout
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"/>
+                <TextView
+                    android:layout_width="76dp"
+                    android:layout_height="wrap_content"
+                    android:gravity="end"
+                    android:paddingEnd="20dp"
+                    android:text="Total"/>
+                <TextView
+                    android:layout_width="76dp"
+                    android:layout_height="wrap_content"
+                    android:gravity="end"
+                    android:paddingEnd="20dp"
+                    android:text="Apps"/>
             </LinearLayout>
 
-        </androidx.cardview.widget.CardView>
-
-
-        <LinearLayout
-            android:id="@+id/headings"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="2dp"
-            android:paddingBottom="4dp">
-            <FrameLayout
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"/>
-            <TextView
-                android:layout_width="100dp"
-                android:layout_height="wrap_content"
-                android:gravity="end"
-                android:paddingEnd="10dp"
-                android:text="Total"/>
-            <TextView
-                android:layout_width="100dp"
-                android:layout_height="wrap_content"
-                android:gravity="end"
-                android:paddingEnd="30dp"
-                android:text="Apps"/>
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1dp"
+                android:background="@android:color/darker_gray"/>
         </LinearLayout>
 
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1dp"
-            android:background="@android:color/darker_gray"/>
-
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/battery_consumer_data_view"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1"/>
-
-        <TextView
-            android:id="@+id/empty_view"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center"
-            android:visibility="gone"
-            android:text="No battery stats available"/>
     </LinearLayout>
 
-    <FrameLayout
-        android:id="@+id/loading_view"
+    <TextView
+        android:id="@+id/empty_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="#AAFFFFFF">
-        <ProgressBar
-            style="?android:attr/progressBarStyleLarge"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:indeterminate="true"/>
-    </FrameLayout>
-</FrameLayout>
+        android:gravity="center"
+        android:visibility="gone"
+        android:text="No battery stats available"/>
+</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index 24b164b..c207135 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -28,29 +28,54 @@
 
 public class BatteryConsumerData {
 
+    public static final String UID_BATTERY_CONSUMER_ID_PREFIX = "APP|";
+    public static final String AGGREGATE_BATTERY_CONSUMER_ID = "SYS|";
+
     enum EntryType {
-        POWER_MODELED,
-        POWER_MEASURED,
-        POWER_CUSTOM,
-        DURATION,
+        UID_TOTAL_POWER,
+        UID_POWER_MODELED,
+        UID_POWER_MEASURED,
+        UID_POWER_CUSTOM,
+        UID_DURATION,
+        DEVICE_TOTAL_POWER,
+        DEVICE_POWER_MODELED,
+        DEVICE_POWER_MEASURED,
+        DEVICE_POWER_CUSTOM,
+        DEVICE_DURATION,
+    }
+
+    enum ConsumerType {
+        UID_BATTERY_CONSUMER,
+        DEVICE_POWER_COMPONENT,
     }
 
     public static class Entry {
-        public String title;
         public EntryType entryType;
-        public double value;
-        public double total;
-        public boolean isSystemBatteryConsumer;
+        public String title;
+        public double value1;
+        public double value2;
     }
 
-    private final BatteryConsumerInfoHelper.BatteryConsumerInfo mBatteryConsumerInfo;
+    private BatteryConsumerInfoHelper.BatteryConsumerInfo mBatteryConsumerInfo;
     private final List<Entry> mEntries = new ArrayList<>();
 
     public BatteryConsumerData(Context context,
             List<BatteryUsageStats> batteryUsageStatsList, String batteryConsumerId) {
+        switch (getConsumerType(batteryConsumerId)) {
+            case UID_BATTERY_CONSUMER:
+                populateForUidBatteryConsumer(context, batteryUsageStatsList, batteryConsumerId);
+                break;
+            case DEVICE_POWER_COMPONENT:
+                populateForAggregateBatteryConsumer(context, batteryUsageStatsList);
+                break;
+        }
+    }
+
+    private void populateForUidBatteryConsumer(
+            Context context, List<BatteryUsageStats> batteryUsageStatsList,
+            String batteryConsumerId) {
         BatteryUsageStats batteryUsageStats = batteryUsageStatsList.get(0);
         BatteryUsageStats modeledBatteryUsageStats = batteryUsageStatsList.get(1);
-
         BatteryConsumer requestedBatteryConsumer = getRequestedBatteryConsumer(batteryUsageStats,
                 batteryConsumerId);
         BatteryConsumer requestedModeledBatteryConsumer = getRequestedBatteryConsumer(
@@ -62,7 +87,7 @@
         }
 
         mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(
-                requestedBatteryConsumer, batteryConsumerId, context.getPackageManager());
+                batteryUsageStats, batteryConsumerId, context.getPackageManager());
 
         double[] totalPowerByComponentMah = new double[BatteryConsumer.POWER_COMPONENT_COUNT];
         double[] totalModeledPowerByComponentMah =
@@ -77,56 +102,152 @@
         computeTotalPowerForCustomComponent(batteryUsageStats, totalCustomPowerByComponentMah);
         computeTotalDuration(batteryUsageStats, totalDurationByComponentMs);
 
+        if (isPowerProfileModelsOnly(requestedBatteryConsumer)) {
+            addEntry("Consumed", EntryType.UID_TOTAL_POWER,
+                    requestedBatteryConsumer.getConsumedPower(),
+                    batteryUsageStats.getAggregateBatteryConsumer(
+                            BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
+                            .getConsumedPower());
+        } else {
+            addEntry("Consumed (measured)", EntryType.UID_TOTAL_POWER,
+                    requestedBatteryConsumer.getConsumedPower(),
+                    batteryUsageStats.getAggregateBatteryConsumer(
+                            BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
+                            .getConsumedPower());
+            addEntry("Consumed (modeled)", EntryType.UID_TOTAL_POWER,
+                    requestedModeledBatteryConsumer.getConsumedPower(),
+                    modeledBatteryUsageStats.getAggregateBatteryConsumer(
+                            BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS)
+                            .getConsumedPower());
+        }
+
         for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
             final String metricTitle = getPowerMetricTitle(component);
             final int powerModel = requestedBatteryConsumer.getPowerModel(component);
             if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
-                addEntry(metricTitle, EntryType.POWER_MODELED,
+                addEntry(metricTitle, EntryType.UID_POWER_MODELED,
                         requestedBatteryConsumer.getConsumedPower(component),
-                        totalPowerByComponentMah[component],
-                        mBatteryConsumerInfo.isSystemBatteryConsumer);
+                        totalPowerByComponentMah[component]
+                );
             } else {
-                addEntry(metricTitle + " (measured)", EntryType.POWER_MEASURED,
+                addEntry(metricTitle + " (measured)", EntryType.UID_POWER_MEASURED,
                         requestedBatteryConsumer.getConsumedPower(component),
-                        totalPowerByComponentMah[component],
-                        mBatteryConsumerInfo.isSystemBatteryConsumer);
-                addEntry(metricTitle + " (modeled)", EntryType.POWER_MODELED,
+                        totalPowerByComponentMah[component]
+                );
+                addEntry(metricTitle + " (modeled)", EntryType.UID_POWER_MODELED,
                         requestedModeledBatteryConsumer.getConsumedPower(component),
-                        totalModeledPowerByComponentMah[component],
-                        mBatteryConsumerInfo.isSystemBatteryConsumer);
+                        totalModeledPowerByComponentMah[component]
+                );
             }
         }
 
         for (int component = 0; component < customComponentCount; component++) {
             final String name = requestedBatteryConsumer.getCustomPowerComponentName(
                     BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component);
-            addEntry(name + " (custom)", EntryType.POWER_CUSTOM,
+            addEntry(name + " (custom)", EntryType.UID_POWER_CUSTOM,
                     requestedBatteryConsumer.getConsumedPowerForCustomComponent(
                             BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component),
-                    totalCustomPowerByComponentMah[component],
-                    mBatteryConsumerInfo.isSystemBatteryConsumer);
+                    totalCustomPowerByComponentMah[component]
+            );
         }
 
         for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
             final String metricTitle = getTimeMetricTitle(component);
-            addEntry(metricTitle, EntryType.DURATION,
+            addEntry(metricTitle, EntryType.UID_DURATION,
                     requestedBatteryConsumer.getUsageDurationMillis(component),
-                    totalDurationByComponentMs[component],
-                    mBatteryConsumerInfo.isSystemBatteryConsumer);
+                    totalDurationByComponentMs[component]
+            );
         }
+
+        mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(batteryUsageStats,
+                batteryConsumerId, context.getPackageManager());
+    }
+
+    private void populateForAggregateBatteryConsumer(Context context,
+            List<BatteryUsageStats> batteryUsageStatsList) {
+        BatteryUsageStats batteryUsageStats = batteryUsageStatsList.get(0);
+        BatteryUsageStats modeledBatteryUsageStats = batteryUsageStatsList.get(1);
+
+        final BatteryConsumer deviceBatteryConsumer =
+                batteryUsageStats.getAggregateBatteryConsumer(
+                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
+        BatteryConsumer appsBatteryConsumer =
+                batteryUsageStats.getAggregateBatteryConsumer(
+                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS);
+
+        BatteryConsumer modeledDeviceBatteryConsumer =
+                modeledBatteryUsageStats.getAggregateBatteryConsumer(
+                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
+        BatteryConsumer modeledAppsBatteryConsumer =
+                modeledBatteryUsageStats.getAggregateBatteryConsumer(
+                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS);
+
+        if (isPowerProfileModelsOnly(deviceBatteryConsumer)) {
+            addEntry("Consumed", EntryType.DEVICE_TOTAL_POWER,
+                    deviceBatteryConsumer.getConsumedPower(),
+                    appsBatteryConsumer.getConsumedPower());
+        } else {
+            addEntry("Consumed (measured)", EntryType.DEVICE_TOTAL_POWER,
+                    deviceBatteryConsumer.getConsumedPower(),
+                    appsBatteryConsumer.getConsumedPower());
+            addEntry("Consumed (modeled)", EntryType.DEVICE_TOTAL_POWER,
+                    modeledDeviceBatteryConsumer.getConsumedPower(),
+                    modeledAppsBatteryConsumer.getConsumedPower());
+        }
+
+        mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(batteryUsageStats,
+                AGGREGATE_BATTERY_CONSUMER_ID, context.getPackageManager());
+
+
+        for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
+            final String metricTitle = getPowerMetricTitle(component);
+            final int powerModel = deviceBatteryConsumer.getPowerModel(component);
+            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+                addEntry(metricTitle, EntryType.DEVICE_POWER_MODELED,
+                        deviceBatteryConsumer.getConsumedPower(component),
+                        appsBatteryConsumer.getConsumedPower(component));
+            } else {
+                addEntry(metricTitle + " (measured)", EntryType.DEVICE_POWER_MEASURED,
+                        deviceBatteryConsumer.getConsumedPower(component),
+                        appsBatteryConsumer.getConsumedPower(component));
+                addEntry(metricTitle + " (modeled)", EntryType.DEVICE_POWER_MODELED,
+                        modeledDeviceBatteryConsumer.getConsumedPower(component),
+                        modeledAppsBatteryConsumer.getConsumedPower(component));
+            }
+        }
+
+        final int customComponentCount =
+                deviceBatteryConsumer.getCustomPowerComponentCount();
+        for (int component = 0; component < customComponentCount; component++) {
+            final String name = deviceBatteryConsumer.getCustomPowerComponentName(
+                    BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component);
+            addEntry(name + " (custom)", EntryType.DEVICE_POWER_CUSTOM,
+                    deviceBatteryConsumer.getConsumedPowerForCustomComponent(
+                            BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component),
+                    appsBatteryConsumer.getConsumedPowerForCustomComponent(
+                            BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID + component));
+        }
+
+        for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
+            final String metricTitle = getTimeMetricTitle(component);
+            addEntry(metricTitle, EntryType.DEVICE_DURATION,
+                    deviceBatteryConsumer.getUsageDurationMillis(component), 0);
+        }
+    }
+
+    private boolean isPowerProfileModelsOnly(BatteryConsumer batteryConsumer) {
+        for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
+            if (batteryConsumer.getPowerModel(component)
+                    != BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+                return false;
+            }
+        }
+        return true;
     }
 
     private BatteryConsumer getRequestedBatteryConsumer(BatteryUsageStats batteryUsageStats,
             String batteryConsumerId) {
-        for (int scope = 0;
-                scope < BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT;
-                scope++) {
-            if (batteryConsumerId(scope).equals(batteryConsumerId)) {
-                return batteryUsageStats.getAggregateBatteryConsumer(scope);
-            }
-        }
-
-        for (BatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
+        for (UidBatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
             if (batteryConsumerId(consumer).equals(batteryConsumerId)) {
                 return consumer;
             }
@@ -136,17 +257,27 @@
     }
 
     static String getPowerMetricTitle(int componentId) {
-        final String componentName = DebugUtils.constantToString(BatteryConsumer.class,
-                "POWER_COMPONENT_", componentId);
-        return componentName.charAt(0) + componentName.substring(1).toLowerCase().replace('_', ' ')
-                + " power";
+        return getPowerComponentName(componentId);
     }
 
     static String getTimeMetricTitle(int componentId) {
-        final String componentName = DebugUtils.constantToString(BatteryConsumer.class,
-                "POWER_COMPONENT_", componentId);
-        return componentName.charAt(0) + componentName.substring(1).toLowerCase().replace('_', ' ')
-                + " time";
+        return getPowerComponentName(componentId) + " time";
+    }
+
+    private static String getPowerComponentName(int componentId) {
+        switch (componentId) {
+            case BatteryConsumer.POWER_COMPONENT_CPU:
+                return "CPU";
+            case BatteryConsumer.POWER_COMPONENT_GNSS:
+                return "GNSS";
+            case BatteryConsumer.POWER_COMPONENT_WIFI:
+                return "Wi-Fi";
+            default:
+                String componentName = DebugUtils.constantToString(BatteryConsumer.class,
+                        "POWER_COMPONENT_", componentId);
+                return componentName.charAt(0) + componentName.substring(1).toLowerCase()
+                        .replace('_', ' ');
+        }
     }
 
     private void computeTotalPower(BatteryUsageStats batteryUsageStats,
@@ -183,14 +314,12 @@
         }
     }
 
-    private void addEntry(String title, EntryType entryType, double amount, double totalAmount,
-            boolean isSystemBatteryConsumer) {
+    private void addEntry(String title, EntryType entryType, double value1, double value2) {
         Entry entry = new Entry();
         entry.title = title;
         entry.entryType = entryType;
-        entry.value = amount;
-        entry.total = totalAmount;
-        entry.isSystemBatteryConsumer = isSystemBatteryConsumer;
+        entry.value1 = value1;
+        entry.value2 = value2;
         mEntries.add(entry);
     }
 
@@ -202,18 +331,15 @@
         return mEntries;
     }
 
-    public static String batteryConsumerId(BatteryConsumer consumer) {
-        if (consumer instanceof UidBatteryConsumer) {
-            return "APP|"
-                    + UserHandle.getUserId(((UidBatteryConsumer) consumer).getUid()) + "|"
-                    + ((UidBatteryConsumer) consumer).getUid();
-        } else {
-            return "";
+    public static ConsumerType getConsumerType(String batteryConsumerId) {
+        if (batteryConsumerId.startsWith(UID_BATTERY_CONSUMER_ID_PREFIX)) {
+            return ConsumerType.UID_BATTERY_CONSUMER;
         }
+        return ConsumerType.DEVICE_POWER_COMPONENT;
     }
 
-    public static String batteryConsumerId(
-            @BatteryUsageStats.AggregateBatteryConsumerScope int scope) {
-        return "SYS|" + scope;
+    public static String batteryConsumerId(UidBatteryConsumer consumer) {
+        return UID_BATTERY_CONSUMER_ID_PREFIX + UserHandle.getUserId(consumer.getUid()) + "|"
+                + consumer.getUid();
     }
 }
\ No newline at end of file
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
index f2d6bca..c6d71c3 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerInfoHelper.java
@@ -16,18 +16,16 @@
 
 package com.android.frameworks.core.batterystatsviewer;
 
-import static com.android.frameworks.core.batterystatsviewer.BatteryConsumerData.batteryConsumerId;
-
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.os.BatteryConsumer;
 import android.os.BatteryUsageStats;
 import android.os.Process;
 import android.os.UidBatteryConsumer;
-import android.util.DebugUtils;
 
 import androidx.annotation.NonNull;
 
+import java.util.List;
+
 class BatteryConsumerInfoHelper {
 
     private static final String SYSTEM_SERVER_PACKAGE_NAME = "android";
@@ -39,93 +37,110 @@
         public ApplicationInfo iconInfo;
         public CharSequence packages;
         public CharSequence details;
-        public boolean isSystemBatteryConsumer;
+        public BatteryConsumerData.ConsumerType consumerType;
     }
 
     @NonNull
     public static BatteryConsumerInfo makeBatteryConsumerInfo(
-            @NonNull BatteryConsumer batteryConsumer, String batteryConsumerId,
+            @NonNull BatteryUsageStats batteryUsageStats, String batteryConsumerId,
             PackageManager packageManager) {
-        BatteryConsumerInfo info = new BatteryConsumerInfo();
-        info.id = batteryConsumerId;
-        info.powerMah = batteryConsumer.getConsumedPower();
-
-        if (batteryConsumer instanceof UidBatteryConsumer) {
-            final UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
-            int uid = uidBatteryConsumer.getUid();
-            info.details = String.format("UID: %d", uid);
-            String packageWithHighestDrain = uidBatteryConsumer.getPackageWithHighestDrain();
-            if (uid == Process.ROOT_UID) {
-                info.label = "<root>";
-            } else {
-                String[] packages = packageManager.getPackagesForUid(uid);
-                String primaryPackageName = null;
-                if (uid == Process.SYSTEM_UID) {
-                    primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
-                } else if (packages != null) {
-                    for (String name : packages) {
-                        primaryPackageName = name;
-                        if (name.equals(packageWithHighestDrain)) {
-                            break;
-                        }
+        BatteryConsumerData.ConsumerType consumerType = BatteryConsumerData.getConsumerType(
+                batteryConsumerId);
+        switch (consumerType) {
+            case UID_BATTERY_CONSUMER:
+                final List<UidBatteryConsumer> consumers =
+                        batteryUsageStats.getUidBatteryConsumers();
+                for (UidBatteryConsumer consumer : consumers) {
+                    if (BatteryConsumerData.batteryConsumerId(consumer).equals(batteryConsumerId)) {
+                        return makeBatteryConsumerInfo(consumer, packageManager);
                     }
                 }
-
-                if (primaryPackageName != null) {
-                    try {
-                        ApplicationInfo applicationInfo =
-                                packageManager.getApplicationInfo(primaryPackageName, 0);
-                        info.label = applicationInfo.loadLabel(packageManager);
-                        info.iconInfo = applicationInfo;
-                    } catch (PackageManager.NameNotFoundException e) {
-                        info.label = primaryPackageName;
-                    }
-                } else if (packageWithHighestDrain != null) {
-                    info.label = packageWithHighestDrain;
-                }
-
-                if (packages != null && packages.length > 0) {
-                    StringBuilder sb = new StringBuilder();
-                    if (primaryPackageName != null) {
-                        sb.append(primaryPackageName);
-                    }
-                    for (String packageName : packages) {
-                        if (packageName.equals(primaryPackageName)) {
-                            continue;
-                        }
-
-                        if (sb.length() != 0) {
-                            sb.append(", ");
-                        }
-                        sb.append(packageName);
-                    }
-
-                    info.packages = sb;
-                }
-            }
-            // Default the app icon to System Server. This includes root, dex2oat and other UIDs.
-            if (info.iconInfo == null) {
-                try {
-                    info.iconInfo =
-                            packageManager.getApplicationInfo(SYSTEM_SERVER_PACKAGE_NAME, 0);
-                } catch (PackageManager.NameNotFoundException nameNotFoundException) {
-                    // Won't happen
-                }
-            }
-        } else {
-            for (int scope = 0;
-                    scope < BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT;
-                    scope++) {
-                if (batteryConsumerId(scope).equals(batteryConsumerId)) {
-                    final String name = DebugUtils.constantToString(BatteryUsageStats.class,
-                            "AGGREGATE_BATTERY_CONSUMER_SCOPE_", scope)
-                            .replace('_', ' ');
-                    info.label = name;
-                    break;
-                }
-            }
+                break;
+            case DEVICE_POWER_COMPONENT:
+                return makeAggregateBatteryConsumerInfo(batteryUsageStats);
         }
 
+        BatteryConsumerInfo info = new BatteryConsumerInfo();
+        info.id = batteryConsumerId;
+        return info;
+    }
+
+    private static BatteryConsumerInfo makeBatteryConsumerInfo(
+            UidBatteryConsumer uidBatteryConsumer, PackageManager packageManager) {
+        BatteryConsumerInfo info = new BatteryConsumerInfo();
+        info.consumerType = BatteryConsumerData.ConsumerType.UID_BATTERY_CONSUMER;
+        info.id = BatteryConsumerData.batteryConsumerId(uidBatteryConsumer);
+        info.powerMah = uidBatteryConsumer.getConsumedPower();
+        int uid = uidBatteryConsumer.getUid();
+        info.details = String.format("UID: %d", uid);
+        String packageWithHighestDrain = uidBatteryConsumer.getPackageWithHighestDrain();
+        if (uid == Process.ROOT_UID) {
+            info.label = "<root>";
+        } else {
+            String[] packages = packageManager.getPackagesForUid(uid);
+            String primaryPackageName = null;
+            if (uid == Process.SYSTEM_UID) {
+                primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
+            } else if (packages != null) {
+                for (String name : packages) {
+                    primaryPackageName = name;
+                    if (name.equals(packageWithHighestDrain)) {
+                        break;
+                    }
+                }
+            }
+
+            if (primaryPackageName != null) {
+                try {
+                    ApplicationInfo applicationInfo =
+                            packageManager.getApplicationInfo(primaryPackageName, 0);
+                    info.label = applicationInfo.loadLabel(packageManager);
+                    info.iconInfo = applicationInfo;
+                } catch (PackageManager.NameNotFoundException e) {
+                    info.label = primaryPackageName;
+                }
+            } else if (packageWithHighestDrain != null) {
+                info.label = packageWithHighestDrain;
+            }
+
+            if (packages != null && packages.length > 0) {
+                StringBuilder sb = new StringBuilder();
+                if (primaryPackageName != null) {
+                    sb.append(primaryPackageName);
+                }
+                for (String packageName : packages) {
+                    if (packageName.equals(primaryPackageName)) {
+                        continue;
+                    }
+
+                    if (sb.length() != 0) {
+                        sb.append(", ");
+                    }
+                    sb.append(packageName);
+                }
+
+                info.packages = sb;
+            }
+        }
+        // Default the app icon to System Server. This includes root, dex2oat and other UIDs.
+        if (info.iconInfo == null) {
+            try {
+                info.iconInfo =
+                        packageManager.getApplicationInfo(SYSTEM_SERVER_PACKAGE_NAME, 0);
+            } catch (PackageManager.NameNotFoundException nameNotFoundException) {
+                // Won't happen
+            }
+        }
+        return info;
+    }
+
+    private static BatteryConsumerInfo makeAggregateBatteryConsumerInfo(
+            BatteryUsageStats batteryUsageStats) {
+        BatteryConsumerInfo info = new BatteryConsumerInfo();
+        info.consumerType = BatteryConsumerData.ConsumerType.DEVICE_POWER_COMPONENT;
+        info.id = BatteryConsumerData.AGGREGATE_BATTERY_CONSUMER_ID;
+        info.powerMah = batteryUsageStats.getConsumedPower();
+        info.label = "Device";
         return info;
     }
 }
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java
index 9e63a35..4469168 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerPickerActivity.java
@@ -21,6 +21,7 @@
 import android.content.pm.PackageManager;
 import android.os.BatteryStatsManager;
 import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
 import android.os.Bundle;
 import android.os.UidBatteryConsumer;
 import android.view.LayoutInflater;
@@ -35,10 +36,12 @@
 import androidx.loader.content.Loader;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
 import com.android.settingslib.utils.AsyncLoaderCompat;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Locale;
@@ -50,10 +53,11 @@
 public class BatteryConsumerPickerActivity extends ComponentActivity {
     private static final String PREF_SELECTED_BATTERY_CONSUMER = "batteryConsumerId";
     private static final int BATTERY_STATS_REFRESH_RATE_MILLIS = 60 * 1000;
+    private static final String FORCE_FRESH_STATS = "force_fresh_stats";
     private BatteryConsumerListAdapter mBatteryConsumerListAdapter;
     private RecyclerView mAppList;
-    private View mLoadingView;
-    private final Runnable mBatteryStatsRefresh = this::loadBatteryStats;
+    private SwipeRefreshLayout mSwipeRefreshLayout;
+    private final Runnable mBatteryStatsRefresh = this::refreshPeriodically;
 
     private interface OnBatteryConsumerSelectedListener {
         void onBatteryConsumerSelected(String batteryConsumerId);
@@ -64,8 +68,11 @@
         super.onCreate(icicle);
 
         setContentView(R.layout.battery_consumer_picker_layout);
-        mLoadingView = findViewById(R.id.loading_view);
 
+        mSwipeRefreshLayout = findViewById(R.id.swipe_refresh);
+        mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_green_light);
+        mSwipeRefreshLayout.setRefreshing(true);
+        mSwipeRefreshLayout.setOnRefreshListener(this::onRefresh);
         mAppList = findViewById(R.id.list_view);
         mAppList.setLayoutManager(new LinearLayoutManager(this));
         mBatteryConsumerListAdapter =
@@ -97,7 +104,7 @@
     @Override
     protected void onResume() {
         super.onResume();
-        loadBatteryStats();
+        refreshPeriodically();
     }
 
     @Override
@@ -106,42 +113,54 @@
         getMainThreadHandler().removeCallbacks(mBatteryStatsRefresh);
     }
 
-    private void loadBatteryStats() {
-        LoaderManager.getInstance(this).restartLoader(0, null,
-                new BatteryConsumerListLoaderCallbacks());
+    private void refreshPeriodically() {
+        loadBatteryUsageStats(false);
         getMainThreadHandler().postDelayed(mBatteryStatsRefresh, BATTERY_STATS_REFRESH_RATE_MILLIS);
     }
 
+    private void onRefresh() {
+        loadBatteryUsageStats(true);
+    }
+
+    private void loadBatteryUsageStats(boolean forceFreshStats) {
+        Bundle args = new Bundle();
+        args.putBoolean(FORCE_FRESH_STATS, forceFreshStats);
+        LoaderManager.getInstance(this).restartLoader(0, args,
+                new BatteryConsumerListLoaderCallbacks());
+    }
+
     private static class BatteryConsumerListLoader extends
             AsyncLoaderCompat<List<BatteryConsumerInfoHelper.BatteryConsumerInfo>> {
         private final BatteryStatsManager mBatteryStatsManager;
         private final PackageManager mPackageManager;
+        private final boolean mForceFreshStats;
 
-        BatteryConsumerListLoader(Context context) {
+        BatteryConsumerListLoader(Context context, boolean forceFreshStats) {
             super(context);
             mBatteryStatsManager = context.getSystemService(BatteryStatsManager.class);
             mPackageManager = context.getPackageManager();
+            mForceFreshStats = forceFreshStats;
         }
 
         @Override
         public List<BatteryConsumerInfoHelper.BatteryConsumerInfo> loadInBackground() {
-            final BatteryUsageStats batteryUsageStats = mBatteryStatsManager.getBatteryUsageStats();
+            final BatteryUsageStatsQuery query = mForceFreshStats
+                    ? new BatteryUsageStatsQuery.Builder().setMaxStatsAgeMs(0).build()
+                    : BatteryUsageStatsQuery.DEFAULT;
+            final BatteryUsageStats batteryUsageStats =
+                    mBatteryStatsManager.getBatteryUsageStats(query);
             List<BatteryConsumerInfoHelper.BatteryConsumerInfo> batteryConsumerList =
                     new ArrayList<>();
 
-            for (int scope = 0;
-                    scope < BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT;
-                    scope++) {
-                batteryConsumerList.add(
-                        BatteryConsumerInfoHelper.makeBatteryConsumerInfo(
-                                batteryUsageStats.getAggregateBatteryConsumer(scope),
-                                BatteryConsumerData.batteryConsumerId(scope),
-                                mPackageManager));
-            }
+            batteryConsumerList.add(
+                    BatteryConsumerInfoHelper.makeBatteryConsumerInfo(
+                            batteryUsageStats,
+                            BatteryConsumerData.AGGREGATE_BATTERY_CONSUMER_ID,
+                            mPackageManager));
 
             for (UidBatteryConsumer consumer : batteryUsageStats.getUidBatteryConsumers()) {
                 batteryConsumerList.add(
-                        BatteryConsumerInfoHelper.makeBatteryConsumerInfo(consumer,
+                        BatteryConsumerInfoHelper.makeBatteryConsumerInfo(batteryUsageStats,
                                 BatteryConsumerData.batteryConsumerId(consumer),
                                 mPackageManager));
             }
@@ -166,7 +185,8 @@
         @Override
         public Loader<List<BatteryConsumerInfoHelper.BatteryConsumerInfo>> onCreateLoader(int id,
                 Bundle args) {
-            return new BatteryConsumerListLoader(BatteryConsumerPickerActivity.this);
+            return new BatteryConsumerListLoader(BatteryConsumerPickerActivity.this,
+                    args.getBoolean(FORCE_FRESH_STATS));
         }
 
         @Override
@@ -174,8 +194,7 @@
                 @NonNull Loader<List<BatteryConsumerInfoHelper.BatteryConsumerInfo>> loader,
                 List<BatteryConsumerInfoHelper.BatteryConsumerInfo> batteryConsumerList) {
             mBatteryConsumerListAdapter.setBatteryConsumerList(batteryConsumerList);
-            mAppList.setVisibility(View.VISIBLE);
-            mLoadingView.setVisibility(View.GONE);
+            mSwipeRefreshLayout.setRefreshing(false);
         }
 
         @Override
@@ -187,7 +206,8 @@
     public class BatteryConsumerListAdapter
             extends RecyclerView.Adapter<BatteryConsumerViewHolder> {
         private final OnBatteryConsumerSelectedListener mListener;
-        private List<BatteryConsumerInfoHelper.BatteryConsumerInfo> mBatteryConsumerList;
+        private List<BatteryConsumerInfoHelper.BatteryConsumerInfo> mBatteryConsumerList =
+                Collections.emptyList();
 
         public BatteryConsumerListAdapter(OnBatteryConsumerSelectedListener listener) {
             mListener = listener;
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
index bb75be4..33ce6bf 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryStatsViewerActivity.java
@@ -36,6 +36,7 @@
 import androidx.loader.content.Loader;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
 import com.android.settingslib.utils.AsyncLoaderCompat;
 
@@ -48,10 +49,10 @@
 
     private static final int BATTERY_STATS_REFRESH_RATE_MILLIS = 60 * 1000;
     private static final int MILLIS_IN_MINUTE = 60000;
-    private static final int LOADER_BATTERY_USAGE_STATS = 1;
+    private static final String FORCE_FRESH_STATS = "force_fresh_stats";
 
     private BatteryStatsDataAdapter mBatteryStatsDataAdapter;
-    private final Runnable mBatteryStatsRefresh = this::loadBatteryStats;
+    private final Runnable mBatteryStatsRefresh = this::refreshPeriodically;
     private String mBatteryConsumerId;
     private TextView mTitleView;
     private TextView mDetailsView;
@@ -59,7 +60,8 @@
     private TextView mPackagesView;
     private View mHeadingsView;
     private RecyclerView mBatteryConsumerDataView;
-    private View mLoadingView;
+    private SwipeRefreshLayout mSwipeRefreshLayout;
+    private View mCardView;
     private View mEmptyView;
     private List<BatteryUsageStats> mBatteryUsageStats;
 
@@ -71,6 +73,12 @@
 
         setContentView(R.layout.battery_stats_viewer_layout);
 
+        mSwipeRefreshLayout = findViewById(R.id.swipe_refresh);
+        mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_green_light);
+        mSwipeRefreshLayout.setRefreshing(true);
+        mSwipeRefreshLayout.setOnRefreshListener(this::onRefresh);
+
+        mCardView = findViewById(R.id.app_card);
         mTitleView = findViewById(android.R.id.title);
         mDetailsView = findViewById(R.id.details);
         mIconView = findViewById(android.R.id.icon);
@@ -82,18 +90,13 @@
         mBatteryStatsDataAdapter = new BatteryStatsDataAdapter();
         mBatteryConsumerDataView.setAdapter(mBatteryStatsDataAdapter);
 
-        mLoadingView = findViewById(R.id.loading_view);
         mEmptyView = findViewById(R.id.empty_view);
-
-        LoaderManager loaderManager = LoaderManager.getInstance(this);
-        loaderManager.restartLoader(LOADER_BATTERY_USAGE_STATS, null,
-                new BatteryUsageStatsLoaderCallbacks());
     }
 
     @Override
     protected void onResume() {
         super.onResume();
-        loadBatteryStats();
+        refreshPeriodically();
     }
 
     @Override
@@ -102,32 +105,46 @@
         getMainThreadHandler().removeCallbacks(mBatteryStatsRefresh);
     }
 
-    private void loadBatteryStats() {
-        LoaderManager loaderManager = LoaderManager.getInstance(this);
-        loaderManager.restartLoader(LOADER_BATTERY_USAGE_STATS, null,
-                new BatteryUsageStatsLoaderCallbacks());
+    private void refreshPeriodically() {
+        loadBatteryUsageStats(false);
         getMainThreadHandler().postDelayed(mBatteryStatsRefresh, BATTERY_STATS_REFRESH_RATE_MILLIS);
     }
 
+    private void onRefresh() {
+        loadBatteryUsageStats(true);
+    }
+
+    private void loadBatteryUsageStats(boolean forceFreshStats) {
+        Bundle args = new Bundle();
+        args.putBoolean(FORCE_FRESH_STATS, forceFreshStats);
+        LoaderManager.getInstance(this).restartLoader(0, args,
+                new BatteryUsageStatsLoaderCallbacks());
+    }
+
     private static class BatteryUsageStatsLoader extends
             AsyncLoaderCompat<List<BatteryUsageStats>> {
         private final BatteryStatsManager mBatteryStatsManager;
+        private final boolean mForceFreshStats;
 
-        BatteryUsageStatsLoader(Context context) {
+        BatteryUsageStatsLoader(Context context, boolean forceFreshStats) {
             super(context);
             mBatteryStatsManager = context.getSystemService(BatteryStatsManager.class);
+            mForceFreshStats = forceFreshStats;
         }
 
         @Override
         public List<BatteryUsageStats> loadInBackground() {
+            final int maxStatsAgeMs = mForceFreshStats ? 0 : BATTERY_STATS_REFRESH_RATE_MILLIS;
             final BatteryUsageStatsQuery queryDefault =
                     new BatteryUsageStatsQuery.Builder()
                             .includePowerModels()
+                            .setMaxStatsAgeMs(maxStatsAgeMs)
                             .build();
             final BatteryUsageStatsQuery queryPowerProfileModeledOnly =
                     new BatteryUsageStatsQuery.Builder()
                             .powerProfileModeledOnly()
                             .includePowerModels()
+                            .setMaxStatsAgeMs(maxStatsAgeMs)
                             .build();
             return mBatteryStatsManager.getBatteryUsageStats(
                     List.of(queryDefault, queryPowerProfileModeledOnly));
@@ -143,7 +160,8 @@
         @NonNull
         @Override
         public Loader<List<BatteryUsageStats>> onCreateLoader(int id, Bundle args) {
-            return new BatteryUsageStatsLoader(BatteryStatsViewerActivity.this);
+            return new BatteryUsageStatsLoader(BatteryStatsViewerActivity.this,
+                    args.getBoolean(FORCE_FRESH_STATS));
         }
 
         @Override
@@ -194,7 +212,8 @@
                 mPackagesView.setVisibility(View.GONE);
             }
 
-            if (batteryConsumerInfo.isSystemBatteryConsumer) {
+            if (batteryConsumerInfo.consumerType
+                    == BatteryConsumerData.ConsumerType.DEVICE_POWER_COMPONENT) {
                 mHeadingsView.setVisibility(View.VISIBLE);
             } else {
                 mHeadingsView.setVisibility(View.GONE);
@@ -210,7 +229,8 @@
             mBatteryConsumerDataView.setVisibility(View.VISIBLE);
         }
 
-        mLoadingView.setVisibility(View.GONE);
+        mCardView.setVisibility(View.VISIBLE);
+        mSwipeRefreshLayout.setRefreshing(false);
     }
 
     private static class BatteryStatsDataAdapter extends
@@ -218,16 +238,16 @@
         public static class ViewHolder extends RecyclerView.ViewHolder {
             public ImageView iconImageView;
             public TextView titleTextView;
-            public TextView amountTextView;
-            public TextView percentTextView;
+            public TextView value1TextView;
+            public TextView value2TextView;
 
             ViewHolder(View itemView) {
                 super(itemView);
 
                 iconImageView = itemView.findViewById(R.id.icon);
                 titleTextView = itemView.findViewById(R.id.title);
-                amountTextView = itemView.findViewById(R.id.amount);
-                percentTextView = itemView.findViewById(R.id.percent);
+                value1TextView = itemView.findViewById(R.id.value1);
+                value2TextView = itemView.findViewById(R.id.value2);
             }
         }
 
@@ -255,57 +275,108 @@
         @Override
         public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
             BatteryConsumerData.Entry entry = mEntries.get(position);
+
             switch (entry.entryType) {
-                case POWER_MODELED:
-                    viewHolder.titleTextView.setText(entry.title);
-                    viewHolder.amountTextView.setText(
-                            String.format(Locale.getDefault(), "%.1f mAh", entry.value));
-                    viewHolder.iconImageView.setImageResource(R.drawable.gm_calculate_24);
-                    viewHolder.itemView.setBackgroundResource(
+                case UID_TOTAL_POWER:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_sum_24, 0);
+                    setPowerText(viewHolder.value1TextView, entry.value1);
+                    setProportionText(viewHolder.value2TextView, entry);
+                    break;
+                case UID_POWER_MODELED:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_calculate_24,
                             R.color.battery_consumer_bg_power_profile);
+                    setPowerText(viewHolder.value1TextView, entry.value1);
+                    setProportionText(viewHolder.value2TextView, entry);
                     break;
-                case POWER_MEASURED:
-                    viewHolder.titleTextView.setText(entry.title);
-                    viewHolder.amountTextView.setText(
-                            String.format(Locale.getDefault(), "%.1f mAh", entry.value));
-                    viewHolder.iconImageView.setImageResource(R.drawable.gm_amp_24);
-                    viewHolder.itemView.setBackgroundResource(
+                case UID_POWER_MEASURED:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_amp_24,
                             R.color.battery_consumer_bg_measured_energy);
+                    setPowerText(viewHolder.value1TextView, entry.value1);
+                    setProportionText(viewHolder.value2TextView, entry);
                     break;
-                case POWER_CUSTOM:
-                    viewHolder.titleTextView.setText(entry.title);
-                    viewHolder.amountTextView.setText(
-                            String.format(Locale.getDefault(), "%.1f mAh", entry.value));
-                    viewHolder.iconImageView.setImageResource(R.drawable.gm_custom_24);
-                    viewHolder.itemView.setBackgroundResource(
+                case UID_POWER_CUSTOM:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_custom_24,
                             R.color.battery_consumer_bg_measured_energy);
+                    setPowerText(viewHolder.value1TextView, entry.value1);
+                    setProportionText(viewHolder.value2TextView, entry);
                     break;
-                case DURATION:
-                    viewHolder.titleTextView.setText(entry.title);
-                    final long durationMs = (long) entry.value;
-                    CharSequence text;
-                    if (durationMs < MILLIS_IN_MINUTE) {
-                        text = String.format(Locale.getDefault(), "%,d ms", durationMs);
-                    } else {
-                        text = String.format(Locale.getDefault(), "%,d m %d s",
-                                durationMs / MILLIS_IN_MINUTE,
-                                (durationMs % MILLIS_IN_MINUTE) / 1000);
-                    }
-
-                    viewHolder.amountTextView.setText(text);
-                    viewHolder.iconImageView.setImageResource(R.drawable.gm_timer_24);
-                    viewHolder.itemView.setBackground(null);
+                case UID_DURATION:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_timer_24, 0);
+                    setDurationText(viewHolder.value1TextView, (long) entry.value1);
+                    setProportionText(viewHolder.value2TextView, entry);
+                    break;
+                case DEVICE_TOTAL_POWER:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_sum_24, 0);
+                    setPowerText(viewHolder.value1TextView, entry.value1);
+                    setPowerText(viewHolder.value2TextView, entry.value2);
+                    break;
+                case DEVICE_POWER_MODELED:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_calculate_24,
+                            R.color.battery_consumer_bg_power_profile);
+                    setPowerText(viewHolder.value1TextView, entry.value1);
+                    setPowerText(viewHolder.value2TextView, entry.value2);
+                    break;
+                case DEVICE_POWER_MEASURED:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_amp_24,
+                            R.color.battery_consumer_bg_measured_energy);
+                    setPowerText(viewHolder.value1TextView, entry.value1);
+                    setPowerText(viewHolder.value2TextView, entry.value2);
+                    break;
+                case DEVICE_POWER_CUSTOM:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_custom_24,
+                            R.color.battery_consumer_bg_measured_energy);
+                    setPowerText(viewHolder.value1TextView, entry.value1);
+                    setPowerText(viewHolder.value2TextView, entry.value2);
+                    break;
+                case DEVICE_DURATION:
+                    setTitleIconAndBackground(viewHolder, entry.title,
+                            R.drawable.gm_timer_24, 0);
+                    setDurationText(viewHolder.value1TextView, (long) entry.value1);
+                    viewHolder.value2TextView.setVisibility(View.GONE);
                     break;
             }
+        }
 
-            double proportion;
-            if (entry.isSystemBatteryConsumer) {
-                proportion = entry.value != 0 ? entry.total * 100 / entry.value : 0;
-            } else {
-                proportion = entry.total != 0 ? entry.value * 100 / entry.total : 0;
-            }
-            viewHolder.percentTextView.setText(
+        private void setTitleIconAndBackground(ViewHolder viewHolder, String title, int icon,
+                int background) {
+            viewHolder.titleTextView.setText(title);
+            viewHolder.iconImageView.setImageResource(icon);
+            viewHolder.itemView.setBackgroundResource(background);
+        }
+
+        private void setProportionText(TextView textView, BatteryConsumerData.Entry entry) {
+            final double proportion = entry.value2 != 0 ? entry.value1 * 100 / entry.value2 : 0;
+            textView.setText(
                     String.format(Locale.getDefault(), "%.1f%%", proportion));
+            textView.setVisibility(View.VISIBLE);
+        }
+
+        private void setPowerText(TextView textView, double powerMah) {
+            textView.setText(String.format(Locale.getDefault(), "%.1f", powerMah));
+            textView.setVisibility(View.VISIBLE);
+        }
+
+        private void setDurationText(TextView textView, long durationMs) {
+            CharSequence text;
+            if (durationMs < MILLIS_IN_MINUTE) {
+                text = String.format(Locale.getDefault(), "%,d ms", durationMs);
+            } else {
+                text = String.format(Locale.getDefault(), "%,d m %d s",
+                        durationMs / MILLIS_IN_MINUTE,
+                        (durationMs % MILLIS_IN_MINUTE) / 1000);
+            }
+
+            textView.setText(text);
+            textView.setVisibility(View.VISIBLE);
         }
     }
 }
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java
index 9e88373..a613e77 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java
@@ -16,18 +16,12 @@
 
 package android.app.appsearch;
 
-
 import static com.google.common.truth.Truth.assertThat;
 
 import android.os.Bundle;
 
-import com.google.common.collect.ImmutableList;
-
 import org.junit.Test;
 
-import java.util.List;
-import java.util.Map;
-
 public class SearchSpecTest {
 
     @Test
@@ -63,32 +57,4 @@
         assertThat(bundle.getInt(SearchSpec.RANKING_STRATEGY_FIELD))
                 .isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE);
     }
-
-    @Test
-    public void testGetProjectionTypePropertyMasks() {
-        SearchSpec searchSpec =
-                new SearchSpec.Builder()
-                        .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
-                        .addProjection("TypeA", ImmutableList.of("field1", "field2.subfield2"))
-                        .addProjection("TypeB", ImmutableList.of("field7"))
-                        .addProjection("TypeC", ImmutableList.of())
-                        .build();
-
-        Map<String, List<String>> typePropertyPathMap = searchSpec.getProjections();
-        assertThat(typePropertyPathMap.keySet()).containsExactly("TypeA", "TypeB", "TypeC");
-        assertThat(typePropertyPathMap.get("TypeA")).containsExactly("field1", "field2.subfield2");
-        assertThat(typePropertyPathMap.get("TypeB")).containsExactly("field7");
-        assertThat(typePropertyPathMap.get("TypeC")).isEmpty();
-    }
-
-    @Test
-    public void testGetRankingStrategy() {
-        SearchSpec searchSpec =
-                new SearchSpec.Builder()
-                        .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
-                        .setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
-                        .build();
-        assertThat(searchSpec.getRankingStrategy())
-                .isEqualTo(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE);
-    }
 }
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaResponseTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaResponseTest.java
new file mode 100644
index 0000000..0bbea42
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaResponseTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class SetSchemaResponseTest {
+    @Test
+    public void testRebuild() {
+        SetSchemaResponse.MigrationFailure failure1 =
+                new SetSchemaResponse.MigrationFailure(
+                        "namespace",
+                        "failure1",
+                        "schemaType",
+                        AppSearchResult.newFailedResult(
+                                AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+        SetSchemaResponse.MigrationFailure failure2 =
+                new SetSchemaResponse.MigrationFailure(
+                        "namespace",
+                        "failure2",
+                        "schemaType",
+                        AppSearchResult.newFailedResult(
+                                AppSearchResult.RESULT_INTERNAL_ERROR, "errorMessage"));
+
+        SetSchemaResponse original =
+                new SetSchemaResponse.Builder()
+                        .addDeletedType("delete1")
+                        .addIncompatibleType("incompatible1")
+                        .addMigratedType("migrated1")
+                        .addMigrationFailure(failure1)
+                        .build();
+        assertThat(original.getDeletedTypes()).containsExactly("delete1");
+        assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
+        assertThat(original.getMigratedTypes()).containsExactly("migrated1");
+        assertThat(original.getMigrationFailures()).containsExactly(failure1);
+
+        SetSchemaResponse rebuild =
+                original.toBuilder()
+                        .addDeletedType("delete2")
+                        .addIncompatibleType("incompatible2")
+                        .addMigratedType("migrated2")
+                        .addMigrationFailure(failure2)
+                        .build();
+
+        // rebuild won't effect the original object
+        assertThat(original.getDeletedTypes()).containsExactly("delete1");
+        assertThat(original.getIncompatibleTypes()).containsExactly("incompatible1");
+        assertThat(original.getMigratedTypes()).containsExactly("migrated1");
+        assertThat(original.getMigrationFailures()).containsExactly(failure1);
+
+        assertThat(rebuild.getDeletedTypes()).containsExactly("delete1", "delete2");
+        assertThat(rebuild.getIncompatibleTypes())
+                .containsExactly("incompatible1", "incompatible2");
+        assertThat(rebuild.getMigratedTypes()).containsExactly("migrated1", "migrated2");
+        assertThat(rebuild.getMigrationFailures()).containsExactly(failure1, failure2);
+    }
+}
diff --git a/core/tests/coretests/src/android/app/appsearch/external/exceptions/IllegalSchemaExceptionTest.java b/core/tests/coretests/src/android/app/appsearch/external/exceptions/IllegalSchemaExceptionTest.java
new file mode 100644
index 0000000..1774d72
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/external/exceptions/IllegalSchemaExceptionTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.appsearch.exceptions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+public class IllegalSchemaExceptionTest {
+    @Test
+    public void testExceptionWithMessage() {
+        IllegalSchemaException e = new IllegalSchemaException("ERROR MESSAGE");
+        assertThat(e.getMessage()).isEqualTo("ERROR MESSAGE");
+        assertThat(e).isInstanceOf(IllegalArgumentException.class);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
index 127cea8..c8564ac 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -24,6 +24,7 @@
 import android.os.BatteryUsageStats;
 import android.os.Parcel;
 import android.os.UidBatteryConsumer;
+import android.os.UserBatteryConsumer;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -31,7 +32,11 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -60,13 +65,42 @@
         validateBatteryUsageStats(inBatteryUsageStats);
     }
 
+    @Test
+    public void testDump() {
+        final BatteryUsageStats stats = buildBatteryUsageStats();
+        final StringWriter out = new StringWriter();
+        try (PrintWriter pw = new PrintWriter(out)) {
+            stats.dump(pw, "  ");
+        }
+        final String dump = out.toString();
+
+        assertThat(dump).contains("Capacity: 4000");
+        assertThat(dump).contains("Computed drain: 30000");
+        assertThat(dump).contains("actual drain: 1000-2000");
+        assertThat(dump).contains("cpu: 20100 apps: 10100 duration: 20s 300ms");
+        assertThat(dump).contains("FOO: 20200 apps: 10200 duration: 20s 400ms");
+        assertThat(dump).contains("UID 2000: 1200 ( screen=300 cpu=400 FOO=500 )");
+        assertThat(dump).contains("User 42: 30.0 ( cpu=10.0 FOO=20.0 )");
+    }
+
+    @Test
+    public void testPowerComponentNames_existAndUnique() {
+        Set<String> allNames = new HashSet<>();
+        for (int i = 0; i < BatteryConsumer.POWER_COMPONENT_COUNT; i++) {
+            assertThat(BatteryConsumer.powerComponentIdToString(i)).isNotNull();
+            allNames.add(BatteryConsumer.powerComponentIdToString(i));
+        }
+        assertThat(allNames).hasSize(BatteryConsumer.POWER_COMPONENT_COUNT);
+    }
+
     private BatteryUsageStats buildBatteryUsageStats() {
         final MockClocks clocks = new MockClocks();
         final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
         final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
 
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[]{"FOO"})
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true)
+                        .setBatteryCapacity(4000)
                         .setDischargePercentage(20)
                         .setDischargedPowerRange(1000, 2000)
                         .setStatsStartTimestamp(1000);
@@ -108,11 +142,22 @@
                 .setUsageDurationForCustomComponentMillis(
                         BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20400);
 
+        builder.getOrCreateUserBatteryConsumerBuilder(42)
+                .setConsumedPower(
+                        BatteryConsumer.POWER_COMPONENT_CPU, 10)
+                .setConsumedPowerForCustomComponent(
+                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 20)
+                .setUsageDurationMillis(
+                        BatteryConsumer.POWER_COMPONENT_CPU, 30)
+                .setUsageDurationForCustomComponentMillis(
+                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 40);
+
         return builder.build();
     }
 
     public void validateBatteryUsageStats(BatteryUsageStats batteryUsageStats) {
         assertThat(batteryUsageStats.getConsumedPower()).isEqualTo(30000);
+        assertThat(batteryUsageStats.getBatteryCapacity()).isEqualTo(4000);
         assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(20);
         assertThat(batteryUsageStats.getDischargedPowerRange().getLower()).isEqualTo(1000);
         assertThat(batteryUsageStats.getDischargedPowerRange().getUpper()).isEqualTo(2000);
@@ -173,5 +218,26 @@
         assertThat(deviceBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1);
         assertThat(deviceBatteryConsumer.getCustomPowerComponentName(
                 BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO");
+
+        final List<UserBatteryConsumer> userBatteryConsumers =
+                batteryUsageStats.getUserBatteryConsumers();
+        for (UserBatteryConsumer userBatteryConsumer : userBatteryConsumers) {
+            if (userBatteryConsumer.getUserId() == 42) {
+                assertThat(userBatteryConsumer.getConsumedPower(
+                        BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10);
+                assertThat(userBatteryConsumer.getConsumedPowerForCustomComponent(
+                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(20);
+                assertThat(userBatteryConsumer.getUsageDurationMillis(
+                        BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(30);
+                assertThat(userBatteryConsumer.getUsageDurationForCustomComponentMillis(
+                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(40);
+                assertThat(userBatteryConsumer.getConsumedPower()).isEqualTo(30);
+                assertThat(userBatteryConsumer.getCustomPowerComponentCount()).isEqualTo(1);
+                assertThat(userBatteryConsumer.getCustomPowerComponentName(
+                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo("FOO");
+            } else {
+                fail("Unexpected user ID " + userBatteryConsumer.getUserId());
+            }
+        }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
index 2d894f5..a70033b 100644
--- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -499,4 +499,84 @@
         assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_DOZE));
         assertEquals(exp, MeasuredEnergyStats.getDisplayPowerBucket(Display.STATE_DOZE_SUSPEND));
     }
+
+    /** Test MeasuredEnergyStats#isSupportEqualTo */
+    @Test
+    public void testIsSupportEqualTo() {
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
+        Arrays.fill(supportedStandardBuckets, true);
+        final String[] customBucketNames = {"A", "B"};
+
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets.clone(),
+                        customBucketNames.clone());
+
+        assertTrue(
+                "All standard and custom bucket supports match",
+                stats.isSupportEqualTo(supportedStandardBuckets, customBucketNames));
+
+        boolean[] differentSupportedStandardBuckets = supportedStandardBuckets.clone();
+        differentSupportedStandardBuckets[0] = !differentSupportedStandardBuckets[0];
+        assertFalse(
+                "Standard bucket support mismatch",
+                stats.isSupportEqualTo(differentSupportedStandardBuckets, customBucketNames));
+
+        assertFalse(
+                "Custom bucket support mismatch",
+                stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"C", "B"}));
+
+        assertFalse(
+                "Fewer custom buckets supported",
+                stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"A"}));
+
+        assertFalse(
+                "More custom bucket supported",
+                stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"A", "B", "C"}));
+
+        assertFalse(
+                "Custom bucket support order changed",
+                stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"B", "A"}));
+    }
+
+    /** Test MeasuredEnergyStats#isSupportEqualTo when holding a null array of custom buckets */
+    @Test
+    public void testIsSupportEqualTo_nullCustomBuckets() {
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
+
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets.clone(), null);
+
+        assertTrue(
+                "Null custom bucket name lists should match",
+                stats.isSupportEqualTo(supportedStandardBuckets, null));
+
+        assertTrue(
+                "Null and empty custom buckets should match",
+                stats.isSupportEqualTo(supportedStandardBuckets, new String[0]));
+
+        assertFalse(
+                "Null custom buckets should not match populated list",
+                stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"A", "B"}));
+    }
+
+    /** Test MeasuredEnergyStats#isSupportEqualTo when holding an empty array of custom buckets */
+    @Test
+    public void testIsSupportEqualTo_emptyCustomBuckets() {
+        final boolean[] supportedStandardBuckets = new boolean[NUMBER_STANDARD_POWER_BUCKETS];
+
+        final MeasuredEnergyStats stats =
+                new MeasuredEnergyStats(supportedStandardBuckets.clone(), new String[0]);
+
+        assertTrue(
+                "Empty custom buckets should match",
+                stats.isSupportEqualTo(supportedStandardBuckets, new String[0]));
+
+        assertTrue(
+                "Empty and null custom buckets should match",
+                stats.isSupportEqualTo(supportedStandardBuckets, null));
+
+        assertFalse(
+                "Empty custom buckets should not match populated list",
+                stats.isSupportEqualTo(supportedStandardBuckets, new String[]{"A", "B"}));
+    }
 }
diff --git a/data/etc/car/com.android.car.cluster.home.xml b/data/etc/car/com.android.car.cluster.home.xml
index 832e5a7..e1d2b18 100644
--- a/data/etc/car/com.android.car.cluster.home.xml
+++ b/data/etc/car/com.android.car.cluster.home.xml
@@ -17,7 +17,6 @@
 <permissions>
     <privapp-permissions package="com.android.car.cluster.home">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
-        <permission name="android.car.permission.ACCESS_PRIVATE_DISPLAY_ID"/>
         <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/car/com.android.carsystemui.xml b/data/etc/car/com.android.carsystemui.xml
index 8c05282..a267d56 100644
--- a/data/etc/car/com.android.carsystemui.xml
+++ b/data/etc/car/com.android.carsystemui.xml
@@ -19,6 +19,7 @@
         <permission name="android.car.permission.ACCESS_CAR_PROJECTION_STATUS"/>
         <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
         <permission name="android.car.permission.CAR_ENROLL_TRUST"/>
+        <permission name="android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL"/>
         <permission name="android.car.permission.CAR_POWER"/>
         <permission name="android.car.permission.CONTROL_CAR_CLIMATE"/>
         <permission name="android.car.permission.CONTROL_CAR_EVS_ACTIVITY"/>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index e222570..51bf6d53 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -255,6 +255,12 @@
             | 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)
@@ -570,10 +576,13 @@
      * accelerated drawing always acts as if {@link #FILTER_BITMAP_FLAG} is set.
      * 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}.</p>
+     * 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>
      */
     public Paint() {
-        this(0);
+        this(DEFAULT_PAINT_FLAGS);
     }
 
     /**
@@ -618,7 +627,7 @@
     /** Restores the paint to its default settings. */
     public void reset() {
         nReset(mNativePaint);
-        setFlags(HIDDEN_DEFAULT_PAINT_FLAGS);
+        setFlags(HIDDEN_DEFAULT_PAINT_FLAGS | DEFAULT_PAINT_FLAGS);
 
         // 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/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index bbbbe69..26f98d8 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -33,9 +33,6 @@
     <!-- Allow PIP to resize via dragging the corner of PiP. -->
     <bool name="config_pipEnableDragCornerResize">false</bool>
 
-    <!-- Allow PIP to enable round corner, see also R.dimen.pip_corner_radius -->
-    <bool name="config_pipEnableRoundCorner">false</bool>
-
     <!-- Animation duration when using long press on recents to dock -->
     <integer name="long_press_dock_anim_duration">250</integer>
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
index 180cceb..7e5fd92 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAnimationController.java
@@ -113,20 +113,18 @@
 
     /**
      * Animator for OneHanded transition animation which supports both alpha and bounds animation.
-     *
-     * @param <T> Type of property to animate, either offset (float)
      */
     // TODO: Refactoring to use SpringAnimation and DynamicAnimation instead of using ValueAnimator
     //  to implement One-Handed transition animation. (b/185129031)
-    public abstract static class OneHandedTransitionAnimator<T> extends ValueAnimator implements
+    public abstract static class OneHandedTransitionAnimator extends ValueAnimator implements
             ValueAnimator.AnimatorUpdateListener,
             ValueAnimator.AnimatorListener {
 
         private final SurfaceControl mLeash;
         private final WindowContainerToken mToken;
-        private T mStartValue;
-        private T mEndValue;
-        private T mCurrentValue;
+        private float mStartValue;
+        private float mEndValue;
+        private float mCurrentValue;
 
         private final List<OneHandedAnimationCallback> mOneHandedAnimationCallbacks =
                 new ArrayList<>();
@@ -137,7 +135,7 @@
         private @TransitionDirection int mTransitionDirection;
 
         private OneHandedTransitionAnimator(WindowContainerToken token, SurfaceControl leash,
-                T startValue, T endValue) {
+                float startValue, float endValue) {
             mLeash = leash;
             mToken = token;
             mStartValue = startValue;
@@ -204,7 +202,7 @@
             mSurfaceTransactionHelper = helper;
         }
 
-        OneHandedTransitionAnimator<T> addOneHandedAnimationCallback(
+        OneHandedTransitionAnimator addOneHandedAnimationCallback(
                 OneHandedAnimationCallback callback) {
             mOneHandedAnimationCallbacks.add(callback);
             return this;
@@ -223,27 +221,27 @@
             return mTransitionDirection;
         }
 
-        OneHandedTransitionAnimator<T> setTransitionDirection(int direction) {
+        OneHandedTransitionAnimator setTransitionDirection(int direction) {
             mTransitionDirection = direction;
             return this;
         }
 
-        T getStartValue() {
+        float getStartValue() {
             return mStartValue;
         }
 
-        T getEndValue() {
+        float getEndValue() {
             return mEndValue;
         }
 
-        void setCurrentValue(T value) {
+        void setCurrentValue(float value) {
             mCurrentValue = value;
         }
 
         /**
          * Updates the {@link #mEndValue}.
          */
-        void updateEndValue(T endValue) {
+        void updateEndValue(float endValue) {
             mEndValue = endValue;
         }
 
@@ -252,10 +250,10 @@
         }
 
         @VisibleForTesting
-        static OneHandedTransitionAnimator<Float> ofYOffset(WindowContainerToken token,
+        static OneHandedTransitionAnimator ofYOffset(WindowContainerToken token,
                 SurfaceControl leash, float startValue, float endValue, Rect displayBounds) {
 
-            return new OneHandedTransitionAnimator<Float>(token, leash, startValue, endValue) {
+            return new OneHandedTransitionAnimator(token, leash, startValue, endValue) {
 
                 private final Rect mTmpRect = new Rect(displayBounds);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
index 2569b78..b4c745f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl
@@ -24,4 +24,12 @@
      * Notifies the listener that the Pip animation is started.
      */
     void onPipAnimationStarted();
+
+    /**
+     * Notifies the listener about PiP round corner radius changes.
+     * Listener can expect an immediate callback the first time they attach.
+     *
+     * @param cornerRadius the pixel value of the corner radius, zero means it's disabled.
+     */
+    void onPipCornerRadiusChanged(int cornerRadius);
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 2b79539..319d57a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -17,7 +17,6 @@
 package com.android.wm.shell.pip;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -30,10 +29,6 @@
  * Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
  */
 public class PipSurfaceTransactionHelper {
-
-    private final boolean mEnableCornerRadius;
-    private int mCornerRadius;
-
     /** for {@link #scale(SurfaceControl.Transaction, SurfaceControl, Rect, Rect)} operation */
     private final Matrix mTmpTransform = new Matrix();
     private final float[] mTmpFloat9 = new float[9];
@@ -41,11 +36,7 @@
     private final RectF mTmpDestinationRectF = new RectF();
     private final Rect mTmpDestinationRect = new Rect();
 
-    public PipSurfaceTransactionHelper(Context context) {
-        final Resources res = context.getResources();
-        mEnableCornerRadius = res.getBoolean(R.bool.config_pipEnableRoundCorner)
-            || SystemProperties.getBoolean("debug.sf.enable_hole_punch_pip", false);
-    }
+    private int mCornerRadius;
 
     /**
      * Called when display size or font size of settings changed
@@ -53,10 +44,10 @@
      * @param context the current context
      */
     public void onDensityOrFontScaleChanged(Context context) {
-        if (mEnableCornerRadius) {
-            final Resources res = context.getResources();
-            mCornerRadius = res.getDimensionPixelSize(R.dimen.pip_corner_radius);
-        }
+        final boolean enableCornerRadius =
+                SystemProperties.getBoolean("debug.sf.enable_hole_punch_pip", false);
+        mCornerRadius = enableCornerRadius
+                ? context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius) : 0;
     }
 
     /**
@@ -194,9 +185,7 @@
      */
     public PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
             boolean applyCornerRadius) {
-        if (mEnableCornerRadius) {
-            tx.setCornerRadius(leash, applyCornerRadius ? mCornerRadius : 0);
-        }
+        tx.setCornerRadius(leash, applyCornerRadius ? mCornerRadius : 0);
         return this;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index fa5caf0..29a483b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -36,6 +36,7 @@
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
@@ -50,6 +51,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.wm.shell.R;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
@@ -428,6 +430,7 @@
 
     private void onDensityOrFontScaleChanged() {
         mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext);
+        onPipCornerRadiusChanged();
     }
 
     private void onOverlayChanged() {
@@ -488,10 +491,6 @@
         mTouchHandler.getMotionHelper().expandLeavePip(false /* skipAnimation */);
     }
 
-    private PipTouchHandler getPipTouchHandler() {
-        return mTouchHandler;
-    }
-
     /**
      * Hides the PIP menu.
      */
@@ -531,6 +530,21 @@
 
     private void setPinnedStackAnimationListener(IPipAnimationListener callback) {
         mPinnedStackAnimationRecentsCallback = callback;
+        onPipCornerRadiusChanged();
+    }
+
+    private void onPipCornerRadiusChanged() {
+        if (mPinnedStackAnimationRecentsCallback != null) {
+            final boolean enableCornerRadius =
+                    SystemProperties.getBoolean("debug.sf.enable_hole_punch_pip", false);
+            final int cornerRadius = enableCornerRadius
+                    ? mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius) : 0;
+            try {
+                mPinnedStackAnimationRecentsCallback.onPipCornerRadiusChanged(cornerRadius);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to call onPipCornerRadiusChanged", e);
+            }
+        }
     }
 
     private Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 2b45346..ecbf0f1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -152,9 +152,8 @@
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
         inflate(context, R.layout.pip_menu, this);
 
-        final boolean enableCornerRadius = mContext.getResources()
-                .getBoolean(R.bool.config_pipEnableRoundCorner)
-                || SystemProperties.getBoolean("debug.sf.enable_hole_punch_pip", false);
+        final boolean enableCornerRadius =
+                SystemProperties.getBoolean("debug.sf.enable_hole_punch_pip", false);
         mBackgroundDrawable = enableCornerRadius
                 ? mContext.getDrawable(R.drawable.pip_menu_background)
                 : new ColorDrawable(Color.BLACK);
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 fd6f0ad9..1f098c2 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
@@ -66,7 +66,7 @@
     // For example, an icon with the foreground 108*108 opaque pixels and it's background
     // also 108*108 pixels, then do not enlarge this icon if only need to show foreground icon.
     private static final float ENLARGE_FOREGROUND_ICON_THRESHOLD = (72f * 72f) / (108f * 108f);
-    private static final float NO_BACKGROUND_SCALE = 1.3f;
+    private static final float NO_BACKGROUND_SCALE = 192f / 160;
     private final Context mContext;
     private final IconProvider mIconProvider;
 
@@ -283,7 +283,8 @@
             } else {
                 final float iconScale = (float) mIconSize / (float) mDefaultIconSize;
                 final int densityDpi = mContext.getResources().getDisplayMetrics().densityDpi;
-                final int scaledIconDpi = (int) (0.5f + iconScale * densityDpi);
+                final int scaledIconDpi =
+                        (int) (0.5f + iconScale * densityDpi * NO_BACKGROUND_SCALE);
                 iconDrawable = mIconProvider.getIcon(mActivityInfo, scaledIconDpi);
                 if (iconDrawable == null) {
                     iconDrawable = mContext.getPackageManager().getDefaultActivityIcon();
@@ -356,7 +357,7 @@
                     Slog.d(TAG, "makeSplashScreenContentView: choose fg icon");
                 }
                 // Reference AdaptiveIcon description, outer is 108 and inner is 72, so we
-                // should enlarge the size 108/72 if we only draw adaptiveIcon's foreground.
+                // scale by 192/160 if we only draw adaptiveIcon's foreground.
                 final float noBgScale =
                         foreIconTester.nonTransparentRatio() < ENLARGE_FOREGROUND_ICON_THRESHOLD
                                 ? NO_BACKGROUND_SCALE : 1f;
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 8fa2236..a1e6832 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
@@ -17,7 +17,6 @@
 package com.android.wm.shell.startingsurface;
 
 import static android.content.Context.CONTEXT_RESTRICTED;
-import static android.content.res.Configuration.EMPTY;
 import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION;
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -54,7 +53,6 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
 
-import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 /**
@@ -92,8 +90,6 @@
  * => makeSplashScreenContentView -> cachePaint(=AdaptiveIconDrawable#draw)
  * => WM#addView -> .. waiting for Choreographer#doFrame -> relayout -> draw -> (draw the Paint
  * directly).
- *
- * @hide
  */
 public class StartingSurfaceDrawer {
     static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
@@ -197,7 +193,7 @@
         }
 
         final Configuration taskConfig = taskInfo.getConfiguration();
-        if (taskConfig != null && !taskConfig.equals(EMPTY)) {
+        if (taskConfig.diffPublicOnly(context.getResources().getConfiguration()) != 0) {
             if (DEBUG_SPLASH_SCREEN) {
                 Slog.d(TAG, "addSplashScreen: creating context based"
                         + " on task Configuration " + taskConfig + " for splash screen");
@@ -226,20 +222,11 @@
             typedArray.recycle();
         }
 
-        int windowFlags = 0;
-        windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-
-        final boolean[] showWallpaper = new boolean[1];
-        getWindowResFromContext(context, a ->
-                showWallpaper[0] = a.getBoolean(R.styleable.Window_windowShowWallpaper, false));
-        if (showWallpaper[0]) {
-            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-        }
-
         final PhoneWindow win = new PhoneWindow(context);
         win.setIsStartingWindow(true);
 
-        CharSequence label = context.getResources().getText(labelRes, null);
+        final Resources res = context.getResources();
+        final CharSequence label = res.getText(labelRes, null);
         // Only change the accessibility title if the label is localized
         if (label != null) {
             win.setTitle(label, true);
@@ -247,7 +234,12 @@
             win.setTitle(nonLocalizedLabel, false);
         }
 
-        win.setType(WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
+        int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        final TypedArray a = context.obtainStyledAttributes(R.styleable.Window);
+        if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
+            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+        }
+        a.recycle();
 
         // Assumes it's safe to show starting windows of launched apps while
         // the keyguard is being hidden. This is okay because starting windows never show
@@ -261,24 +253,20 @@
         // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
         // flag because we do know that the next window will take input
         // focus, so we want to get the IME window up on top of us right away.
-        win.setFlags(windowFlags
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
-                windowFlags
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+        windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        win.setFlags(windowFlags, windowFlags);
 
         final int iconRes = activityInfo.getIconResource();
         final int logoRes = activityInfo.getLogoResource();
         win.setDefaultIcon(iconRes);
         win.setDefaultLogo(logoRes);
 
-        win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.MATCH_PARENT);
-
         final WindowManager.LayoutParams params = win.getAttributes();
+        params.type = WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+        params.width = WindowManager.LayoutParams.MATCH_PARENT;
+        params.height = WindowManager.LayoutParams.MATCH_PARENT;
         params.token = appToken;
         params.packageName = activityInfo.packageName;
         params.windowAnimations = win.getWindowStyle().getResourceId(
@@ -289,10 +277,7 @@
         params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
         params.format = PixelFormat.RGBA_8888;
 
-        final Resources res = context.getResources();
-        final boolean supportsScreen = res != null && (res.getCompatibilityInfo() != null
-                && res.getCompatibilityInfo().supportsScreen());
-        if (!supportsScreen) {
+        if (!res.getCompatibilityInfo().supportsScreen()) {
             params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
         }
 
@@ -337,7 +322,7 @@
 
         try {
             final View view = win.getDecorView();
-            final WindowManager wm = mContext.getSystemService(WindowManager.class);
+            final WindowManager wm = context.getSystemService(WindowManager.class);
             postAddWindow(taskId, appToken, view, wm, params);
 
             // We use the splash screen worker thread to create SplashScreenView while adding the
@@ -505,12 +490,6 @@
         }
     }
 
-    private void getWindowResFromContext(Context ctx, Consumer<TypedArray> consumer) {
-        final TypedArray a = ctx.obtainStyledAttributes(R.styleable.Window);
-        consumer.accept(a);
-        a.recycle();
-    }
-
     /**
      * Record the view or surface for a starting window.
      */
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 882d382..8ef1df6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -68,7 +68,7 @@
     @Before
     public void setUp() throws Exception {
         mPipAnimationController = new PipAnimationController(
-                new PipSurfaceTransactionHelper(mContext));
+                new PipSurfaceTransactionHelper());
         mLeash = new SurfaceControl.Builder()
                 .setContainerLayer()
                 .setName("FakeLeash")
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 7e45f95..320106a 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -221,6 +221,16 @@
     for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
       iter2->dynamic_ref_table->addMapping(String16(package_name.c_str(), package_name.size()),
                                            iter->dynamic_ref_table->mAssignedPackageId);
+
+      // Add the alias resources to the dynamic reference table of every package group. Since
+      // staging aliases can only be defined by the framework package (which is not a shared
+      // library), the compile-time package id of the framework is the same across all packages
+      // that compile against the framework.
+      for (const auto& package : iter->packages_) {
+        for (const auto& entry : package.loaded_package_->GetAliasResourceIdMap()) {
+          iter2->dynamic_ref_table->addAlias(entry.first, entry.second);
+        }
+      }
     }
   }
 }
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index cb620cc..d17c328 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -41,6 +41,7 @@
 
 namespace android {
 
+constexpr const static int kFrameworkPackageId = 0x01;
 constexpr const static int kAppPackageId = 0x7f;
 
 namespace {
@@ -675,6 +676,42 @@
         }
       } break;
 
+      case RES_TABLE_STAGED_ALIAS_TYPE: {
+        if (loaded_package->package_id_ != kFrameworkPackageId) {
+          LOG(WARNING) << "Alias chunk ignored for non-framework package '"
+                       << loaded_package->package_name_ << "'";
+          break;
+        }
+
+        std::unordered_set<uint32_t> finalized_ids;
+        const auto lib_alias = child_chunk.header<ResTable_staged_alias_header>();
+        if (!lib_alias) {
+          return {};
+        }
+        const auto entry_begin = child_chunk.data_ptr().convert<ResTable_staged_alias_entry>();
+        const auto entry_end = entry_begin + dtohl(lib_alias->count);
+        for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
+          if (!entry_iter) {
+            return {};
+          }
+          auto finalized_id = dtohl(entry_iter->finalizedResId);
+          if (!finalized_ids.insert(finalized_id).second) {
+            LOG(ERROR) << StringPrintf("Repeated finalized resource id '%08x' in staged aliases.",
+                                       finalized_id);
+            return {};
+          }
+
+          auto staged_id = dtohl(entry_iter->stagedResId);
+          auto [_, success] = loaded_package->alias_id_map_.insert(std::make_pair(staged_id,
+                                                                                  finalized_id));
+          if (!success) {
+            LOG(ERROR) << StringPrintf("Repeated staged resource id '%08x' in staged aliases.",
+                                       staged_id);
+            return {};
+          }
+        }
+      } break;
+
       default:
         LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
         break;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 30500ab..cae2d0b 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -7079,6 +7079,10 @@
     mLookupTable[buildPackageId] = runtimePackageId;
 }
 
+void DynamicRefTable::addAlias(uint32_t stagedId, uint32_t finalizedId) {
+  mAliasId[stagedId] = finalizedId;
+}
+
 status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
     uint32_t res = *resId;
     size_t packageId = Res_GETPACKAGE(res) + 1;
@@ -7088,8 +7092,16 @@
         return NO_ERROR;
     }
 
-    if (packageId == APP_PACKAGE_ID && !mAppAsLib) {
-        // No lookup needs to be done, app package IDs are absolute.
+    auto alias_id = mAliasId.find(res);
+    if (alias_id != mAliasId.end()) {
+      // Rewrite the resource id to its alias resource id. Since the alias resource id is a
+      // compile-time id, it still needs to be resolved further.
+      res = alias_id->second;
+    }
+
+    if (packageId == SYS_PACKAGE_ID || (packageId == APP_PACKAGE_ID && !mAppAsLib)) {
+        // No lookup needs to be done, app and framework package IDs are absolute.
+        *resId = res;
         return NO_ERROR;
     }
 
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 3b222c5..9bbdede 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -17,6 +17,7 @@
 #ifndef LOADEDARSC_H_
 #define LOADEDARSC_H_
 
+#include <map>
 #include <memory>
 #include <set>
 #include <vector>
@@ -171,51 +172,51 @@
       incfs::verified_map_ptr<ResTable_type> type_chunk, uint32_t offset);
 
   // Returns the string pool where type names are stored.
-  inline const ResStringPool* GetTypeStringPool() const {
+  const ResStringPool* GetTypeStringPool() const {
     return &type_string_pool_;
   }
 
   // Returns the string pool where the names of resource entries are stored.
-  inline const ResStringPool* GetKeyStringPool() const {
+  const ResStringPool* GetKeyStringPool() const {
     return &key_string_pool_;
   }
 
-  inline const std::string& GetPackageName() const {
+  const std::string& GetPackageName() const {
     return package_name_;
   }
 
-  inline int GetPackageId() const {
+  int GetPackageId() const {
     return package_id_;
   }
 
   // Returns true if this package is dynamic (shared library) and needs to have an ID assigned.
-  inline bool IsDynamic() const {
+  bool IsDynamic() const {
     return (property_flags_ & PROPERTY_DYNAMIC) != 0;
   }
 
   // Returns true if this package is a Runtime Resource Overlay.
-  inline bool IsOverlay() const {
+  bool IsOverlay() const {
     return (property_flags_ & PROPERTY_OVERLAY) != 0;
   }
 
   // Returns true if this package originates from a system provided resource.
-  inline bool IsSystem() const {
+  bool IsSystem() const {
     return (property_flags_ & PROPERTY_SYSTEM) != 0;
   }
 
   // Returns true if this package is a custom loader and should behave like an overlay.
-  inline bool IsCustomLoader() const {
+  bool IsCustomLoader() const {
     return (property_flags_ & PROPERTY_LOADER) != 0;
   }
 
-  inline package_property_t GetPropertyFlags() const {
+  package_property_t GetPropertyFlags() const {
     return property_flags_;
   }
 
   // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a
   // package could have been assigned a different package ID than what this LoadedPackage was
   // compiled with. AssetManager rewrites the package IDs so that they are compatible at runtime.
-  inline const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const {
+  const std::vector<DynamicPackageEntry>& GetDynamicPackageMap() const {
     return dynamic_package_map_;
   }
 
@@ -270,6 +271,10 @@
     return overlayable_map_;
   }
 
+  const std::map<uint32_t, uint32_t>& GetAliasResourceIdMap() const {
+    return alias_id_map_;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
 
@@ -287,6 +292,7 @@
   ByteBucketArray<uint32_t> resource_ids_;
   std::vector<DynamicPackageEntry> dynamic_package_map_;
   std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
+  std::map<uint32_t, uint32_t> alias_id_map_;
 
   // A map of overlayable name to actor
   std::unordered_map<std::string, std::string> overlayable_map_;
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 17c1404..3d66244 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -39,6 +39,7 @@
 #include <android/configuration.h>
 
 #include <array>
+#include <map>
 #include <memory>
 
 namespace android {
@@ -229,30 +230,31 @@
 };
 
 enum {
-    RES_NULL_TYPE               = 0x0000,
-    RES_STRING_POOL_TYPE        = 0x0001,
-    RES_TABLE_TYPE              = 0x0002,
-    RES_XML_TYPE                = 0x0003,
+    RES_NULL_TYPE                     = 0x0000,
+    RES_STRING_POOL_TYPE              = 0x0001,
+    RES_TABLE_TYPE                    = 0x0002,
+    RES_XML_TYPE                      = 0x0003,
 
     // Chunk types in RES_XML_TYPE
-    RES_XML_FIRST_CHUNK_TYPE    = 0x0100,
-    RES_XML_START_NAMESPACE_TYPE= 0x0100,
-    RES_XML_END_NAMESPACE_TYPE  = 0x0101,
-    RES_XML_START_ELEMENT_TYPE  = 0x0102,
-    RES_XML_END_ELEMENT_TYPE    = 0x0103,
-    RES_XML_CDATA_TYPE          = 0x0104,
-    RES_XML_LAST_CHUNK_TYPE     = 0x017f,
+    RES_XML_FIRST_CHUNK_TYPE          = 0x0100,
+    RES_XML_START_NAMESPACE_TYPE      = 0x0100,
+    RES_XML_END_NAMESPACE_TYPE        = 0x0101,
+    RES_XML_START_ELEMENT_TYPE        = 0x0102,
+    RES_XML_END_ELEMENT_TYPE          = 0x0103,
+    RES_XML_CDATA_TYPE                = 0x0104,
+    RES_XML_LAST_CHUNK_TYPE           = 0x017f,
     // This contains a uint32_t array mapping strings in the string
     // pool back to resource identifiers.  It is optional.
-    RES_XML_RESOURCE_MAP_TYPE   = 0x0180,
+    RES_XML_RESOURCE_MAP_TYPE         = 0x0180,
 
     // Chunk types in RES_TABLE_TYPE
-    RES_TABLE_PACKAGE_TYPE      = 0x0200,
-    RES_TABLE_TYPE_TYPE         = 0x0201,
-    RES_TABLE_TYPE_SPEC_TYPE    = 0x0202,
-    RES_TABLE_LIBRARY_TYPE      = 0x0203,
-    RES_TABLE_OVERLAYABLE_TYPE  = 0x0204,
+    RES_TABLE_PACKAGE_TYPE            = 0x0200,
+    RES_TABLE_TYPE_TYPE               = 0x0201,
+    RES_TABLE_TYPE_SPEC_TYPE          = 0x0202,
+    RES_TABLE_LIBRARY_TYPE            = 0x0203,
+    RES_TABLE_OVERLAYABLE_TYPE        = 0x0204,
     RES_TABLE_OVERLAYABLE_POLICY_TYPE = 0x0205,
+    RES_TABLE_STAGED_ALIAS_TYPE       = 0x0206,
 };
 
 /**
@@ -1639,6 +1641,29 @@
 };
 
 /**
+ * A map that allows rewriting staged (non-finalized) resource ids to their finalized counterparts.
+ */
+struct ResTable_staged_alias_header
+{
+    struct ResChunk_header header;
+
+    // The number of ResTable_staged_alias_entry that follow this header.
+    uint32_t count;
+};
+
+/**
+ * Maps the staged (non-finalized) resource id to its finalized resource id.
+ */
+struct ResTable_staged_alias_entry
+{
+  // The compile-time staged resource id to rewrite.
+  uint32_t stagedResId;
+
+  // The compile-time finalized resource id to which the staged resource id should be rewritten.
+  uint32_t finalizedResId;
+};
+
+/**
  * Specifies the set of resources that are explicitly allowed to be overlaid by RROs.
  */
 struct ResTable_overlayable_header
@@ -1751,6 +1776,8 @@
 
     void addMapping(uint8_t buildPackageId, uint8_t runtimePackageId);
 
+    void addAlias(uint32_t stagedId, uint32_t finalizedId);
+
     // Returns whether or not the value must be looked up.
     bool requiresLookup(const Res_value* value) const;
 
@@ -1768,6 +1795,7 @@
     uint8_t                         mLookupTable[256];
     KeyedVector<String16, uint8_t>  mEntries;
     bool                            mAppAsLib;
+    std::map<uint32_t, uint32_t>    mAliasId;
 };
 
 bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 0212309..c6ab8a2 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -583,6 +583,7 @@
         "libhwui_defaults",
         "android_graphics_apex",
         "android_graphics_jni",
+        "linker_hugepage_aligned",
     ],
     export_header_lib_headers: ["android_graphics_apex_headers"],
     target: {
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index cf3ef40b..a164233 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -150,9 +150,19 @@
     }
 }
 
+static inline void applyMatrix(const SkMatrix& transform, SkRect* rect) {
+    return applyMatrix(&transform, rect);
+}
+
 static inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
     if (in.isEmpty()) return;
     SkRect temp(in);
+    if (Properties::stretchEffectBehavior == StretchEffectBehavior::LinearScale) {
+        const StretchEffect& stretch = props.layerProperties().getStretchEffect();
+        if (!stretch.isEmpty()) {
+            applyMatrix(stretch.makeLinearStretch(props.getWidth(), props.getHeight()), &temp);
+        }
+    }
     applyMatrix(props.getTransformMatrix(), &temp);
     if (props.getStaticMatrix()) {
         applyMatrix(props.getStaticMatrix(), &temp);
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 7af0a22..9ed801b 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -84,6 +84,8 @@
 bool Properties::useHintManager = true;
 int Properties::targetCpuTimePercentage = 70;
 
+StretchEffectBehavior Properties::stretchEffectBehavior = StretchEffectBehavior::ShaderHWUI;
+
 bool Properties::load() {
     bool prevDebugLayersUpdates = debugLayersUpdates;
     bool prevDebugOverdraw = debugOverdraw;
@@ -135,6 +137,10 @@
     targetCpuTimePercentage = base::GetIntProperty(PROPERTY_TARGET_CPU_TIME_PERCENTAGE, 70);
     if (targetCpuTimePercentage <= 0 || targetCpuTimePercentage > 100) targetCpuTimePercentage = 70;
 
+    int stretchType = base::GetIntProperty(PROPERTY_STRETCH_EFFECT_TYPE, 0);
+    stretchType = std::clamp(stretchType, 0, static_cast<int>(StretchEffectBehavior::LinearScale));
+    stretchEffectBehavior = static_cast<StretchEffectBehavior>(stretchType);
+
     return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw);
 }
 
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 01c1571..9d2b617 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -171,6 +171,8 @@
  */
 #define PROPERTY_TARGET_CPU_TIME_PERCENTAGE "debug.hwui.target_cpu_time_percent"
 
+#define PROPERTY_STRETCH_EFFECT_TYPE "debug.hwui.stretch_mode"
+
 /**
  * Property for whether this is running in the emulator.
  */
@@ -197,6 +199,12 @@
 
 enum class RenderPipelineType { SkiaGL, SkiaVulkan, NotInitialized = 128 };
 
+enum class StretchEffectBehavior {
+    ShaderHWUI, // Stretch shader in HWUI only, matrix scale in SF
+    Shader, // Stretch shader in both HWUI and SF
+    LinearScale // Linear stretch everywhere
+};
+
 /**
  * Renderthread-only singleton which manages several static rendering properties. Most of these
  * are driven by system properties which are queried once at initialization, and again if init()
@@ -270,6 +278,8 @@
     static bool useHintManager;
     static int targetCpuTimePercentage;
 
+    static StretchEffectBehavior stretchEffectBehavior;
+
 private:
     static ProfileType sProfileType;
     static bool sDisableProfileBars;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index fce2e1f..64abd94 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -477,6 +477,14 @@
             }
         }
     }
+
+    if (Properties::stretchEffectBehavior == StretchEffectBehavior::LinearScale) {
+        const StretchEffect& stretch = properties().layerProperties().getStretchEffect();
+        if (!stretch.isEmpty()) {
+            matrix.multiply(
+                    stretch.makeLinearStretch(properties().getWidth(), properties().getHeight()));
+        }
+    }
 }
 
 const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 5540e2d..cd622eb 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -553,7 +553,7 @@
     bool promotedToLayer() const {
         return mLayerProperties.mType == LayerType::None && fitsOnLayer() &&
                (mComputedFields.mNeedLayerForFunctors || mLayerProperties.mImageFilter != nullptr ||
-                !mLayerProperties.getStretchEffect().isEmpty() ||
+                mLayerProperties.getStretchEffect().requiresLayer() ||
                 (!MathUtils::isZero(mPrimitiveFields.mAlpha) && mPrimitiveFields.mAlpha < 1 &&
                  mPrimitiveFields.mHasOverlappingRendering));
     }
diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h
index 6d517ac..3b3067d 100644
--- a/libs/hwui/effects/StretchEffect.h
+++ b/libs/hwui/effects/StretchEffect.h
@@ -16,10 +16,12 @@
 
 #pragma once
 
+#include "Properties.h"
 #include "utils/MathUtils.h"
 
 #include <SkImage.h>
 #include <SkImageFilter.h>
+#include <SkMatrix.h>
 #include <SkPoint.h>
 #include <SkRect.h>
 #include <SkRuntimeEffect.h>
@@ -99,6 +101,19 @@
 
     const SkVector getStretchDirection() const { return mStretchDirection; }
 
+    SkMatrix makeLinearStretch(float width, float height) const {
+        SkMatrix matrix;
+        auto [sX, sY] = getStretchDirection();
+        matrix.setScale(1 + std::abs(sX), 1 + std::abs(sY), sX > 0 ? 0 : width,
+                        sY > 0 ? 0 : height);
+        return matrix;
+    }
+
+    bool requiresLayer() const {
+        return !(isEmpty() ||
+                 Properties::stretchEffectBehavior == StretchEffectBehavior::LinearScale);
+    }
+
 private:
     static sk_sp<SkRuntimeEffect> getStretchEffect();
     mutable SkVector mStretchDirection{0, 0};
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index f92c32c..cd0783f 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -573,7 +573,9 @@
             const RenderProperties& props = node.properties();
 
             uirenderer::Rect bounds(props.getWidth(), props.getHeight());
-            if (info.stretchEffectCount) {
+            bool useStretchShader = Properties::stretchEffectBehavior !=
+                StretchEffectBehavior::LinearScale;
+            if (useStretchShader && info.stretchEffectCount) {
                 handleStretchEffect(info, bounds);
             }
 
@@ -678,30 +680,32 @@
             stretchTargetBounds(*effect, result.width, result.height,
                                 childRelativeBounds,targetBounds);
 
-            JNIEnv* env = jnienv();
+            if (Properties::stretchEffectBehavior == StretchEffectBehavior::Shader) {
+                JNIEnv* env = jnienv();
 
-            jobject localref = env->NewLocalRef(mWeakRef);
-            if (CC_UNLIKELY(!localref)) {
-                env->DeleteWeakGlobalRef(mWeakRef);
-                mWeakRef = nullptr;
-                return;
-            }
+                jobject localref = env->NewLocalRef(mWeakRef);
+                if (CC_UNLIKELY(!localref)) {
+                    env->DeleteWeakGlobalRef(mWeakRef);
+                    mWeakRef = nullptr;
+                    return;
+                }
 #ifdef __ANDROID__  // Layoutlib does not support CanvasContext
-            SkVector stretchDirection = effect->getStretchDirection();
-            env->CallVoidMethod(localref, gPositionListener_ApplyStretchMethod,
-                                info.canvasContext.getFrameNumber(),
-                                result.width,
-                                result.height,
-                                stretchDirection.fX,
-                                stretchDirection.fY,
-                                effect->maxStretchAmountX,
-                                effect->maxStretchAmountY,
-                                childRelativeBounds.left(),
-                                childRelativeBounds.top(),
-                                childRelativeBounds.right(),
-                                childRelativeBounds.bottom());
+                SkVector stretchDirection = effect->getStretchDirection();
+                env->CallVoidMethod(localref, gPositionListener_ApplyStretchMethod,
+                                    info.canvasContext.getFrameNumber(),
+                                    result.width,
+                                    result.height,
+                                    stretchDirection.fX,
+                                    stretchDirection.fY,
+                                    effect->maxStretchAmountX,
+                                    effect->maxStretchAmountY,
+                                    childRelativeBounds.left(),
+                                    childRelativeBounds.top(),
+                                    childRelativeBounds.right(),
+                                    childRelativeBounds.bottom());
 #endif
-            env->DeleteLocalRef(localref);
+                env->DeleteLocalRef(localref);
+            }
         }
 
         void doUpdatePositionAsync(jlong frameNumber, jint left, jint top,
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 1ae06d0..0b43f09 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -175,7 +175,7 @@
                             float alphaMultiplier, SkPaint* paint) {
     if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
         properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr ||
-        properties.getImageFilter() != nullptr || !properties.getStretchEffect().isEmpty()) {
+        properties.getImageFilter() != nullptr || properties.getStretchEffect().requiresLayer()) {
         paint->setAlpha(properties.alpha() * alphaMultiplier);
         paint->setBlendMode(properties.xferMode());
         paint->setColorFilter(sk_ref_sp(properties.getColorFilter()));
@@ -247,7 +247,8 @@
             }
 
             const StretchEffect& stretch = properties.layerProperties().getStretchEffect();
-            if (stretch.isEmpty()) {
+            if (stretch.isEmpty() ||
+                Properties::stretchEffectBehavior == StretchEffectBehavior::LinearScale) {
                 // If we don't have any stretch effects, issue the filtered
                 // canvas draw calls to make sure we still punch a hole
                 // with the same canvas transformation + clip into the target
@@ -326,6 +327,13 @@
             canvas->concat(*properties.getTransformMatrix());
         }
     }
+    if (Properties::stretchEffectBehavior == StretchEffectBehavior::LinearScale) {
+        const StretchEffect& stretch = properties.layerProperties().getStretchEffect();
+        if (!stretch.isEmpty()) {
+            canvas->concat(
+                    stretch.makeLinearStretch(properties.getWidth(), properties.getHeight()));
+        }
+    }
     const bool isLayer = properties.effectiveLayerType() != LayerType::None;
     int clipFlags = properties.getClippingFlags();
     if (properties.getAlpha() < 1) {
diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp
index e48ecf4..0b995bc 100644
--- a/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp
+++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp
@@ -126,6 +126,12 @@
     mCurrentValues.insert({valueName, {units, value}});
 }
 
+bool SkiaMemoryTracer::hasOutput() {
+    // process any remaining elements
+    processElement();
+    return mResults.size() > 0;
+}
+
 void SkiaMemoryTracer::logOutput(String8& log) {
     // process any remaining elements
     processElement();
diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.h b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h
index e9a7981..b393b07 100644
--- a/libs/hwui/pipeline/skia/SkiaMemoryTracer.h
+++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h
@@ -34,6 +34,7 @@
     SkiaMemoryTracer(const char* categoryKey, bool itemizeType);
     ~SkiaMemoryTracer() override {}
 
+    bool hasOutput();
     void logOutput(String8& log);
     void logTotals(String8& log);
 
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 100bfb6..4658035 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -137,9 +137,10 @@
     int mCaptureSequence = 0;
 
     // Multi frame serialization stream and writer used when serializing more than one frame.
+    std::unique_ptr<SkSharingSerialContext> mSerialContext;  // Must be declared before any other
+                                                             // serializing member
     std::unique_ptr<SkFILEWStream> mOpenMultiPicStream;
     sk_sp<SkDocument> mMultiPic;
-    std::unique_ptr<SkSharingSerialContext> mSerialContext;
 
     /**
      * mRecorder holds the current picture recorder when serializing in either SingleFrameSKP or
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index d998e50..5047be9 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -140,7 +140,6 @@
     log.appendFormat("  Size: %.2f kB \n", SkGraphics::GetFontCacheUsed() / 1024.0f);
     log.appendFormat("  Glyph Count: %d \n", SkGraphics::GetFontCacheCountUsed());
 
-    log.appendFormat("CPU Caches:\n");
     std::vector<skiapipeline::ResourcePair> cpuResourceMap = {
             {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
             {"skia/sk_resource_cache/rrect-blur_", "Masks"},
@@ -149,20 +148,20 @@
     };
     skiapipeline::SkiaMemoryTracer cpuTracer(cpuResourceMap, false);
     SkGraphics::DumpMemoryStatistics(&cpuTracer);
-    cpuTracer.logOutput(log);
+    if (cpuTracer.hasOutput()) {
+        log.appendFormat("CPU Caches:\n");
+        cpuTracer.logOutput(log);
+    }
 
-    log.appendFormat("GPU Caches:\n");
     skiapipeline::SkiaMemoryTracer gpuTracer("category", true);
     mGrContext->dumpMemoryStatistics(&gpuTracer);
-    gpuTracer.logOutput(log);
+    if (gpuTracer.hasOutput()) {
+        log.appendFormat("GPU Caches:\n");
+        gpuTracer.logOutput(log);
+    }
 
-    log.appendFormat("Other Caches:\n");
-    log.appendFormat("                         Current / Maximum\n");
-
-    if (renderState) {
-        if (renderState->mActiveLayers.size() > 0) {
-            log.appendFormat("  Layer Info:\n");
-        }
+    if (renderState && renderState->mActiveLayers.size() > 0) {
+        log.appendFormat("Layer Info:\n");
 
         const char* layerType = Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL
                                         ? "GlLayer"
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index bba2207..bae1ab5 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -467,11 +467,11 @@
     mRenderThread.pushBackFrameCallback(this);
 }
 
-void CanvasContext::draw() {
+nsecs_t CanvasContext::draw() {
     if (auto grContext = getGrContext()) {
         if (grContext->abandoned()) {
             LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw");
-            return;
+            return 0;
         }
     }
     SkRect dirty;
@@ -486,7 +486,7 @@
             std::invoke(func, mFrameNumber);
         }
         mFrameCompleteCallbacks.clear();
-        return;
+        return 0;
     }
 
     ScopedActiveContext activeContext(this);
@@ -616,6 +616,7 @@
     }
 
     mRenderThread.cacheManager().onFrameCompleted();
+    return mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration);
 }
 
 void CanvasContext::reportMetricsWithPresentTime() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index af1ebb2..4f8e4ca 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -127,7 +127,8 @@
     void setColorMode(ColorMode mode);
     bool makeCurrent();
     void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
-    void draw();
+    // Returns the DequeueBufferDuration.
+    nsecs_t draw();
     void destroy();
 
     // IFrameCallback, Choreographer-driven frame callback entry point
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index cb92aa1..8448b87 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -18,6 +18,7 @@
 
 #include <utils/Log.h>
 #include <utils/TraceUtils.h>
+#include <algorithm>
 
 #include "../DeferredLayerUpdater.h"
 #include "../DisplayList.h"
@@ -91,6 +92,7 @@
 void DrawFrameTask::run() {
     const int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
     ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId);
+    nsecs_t syncDelayDuration = systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued;
 
     bool canUnblockUiThread;
     bool canDrawThisFrame;
@@ -124,8 +126,9 @@
                 [callback, frameNr = context->getFrameNumber()]() { callback(frameNr); });
     }
 
+    nsecs_t dequeueBufferDuration = 0;
     if (CC_LIKELY(canDrawThisFrame)) {
-        context->draw();
+        dequeueBufferDuration = context->draw();
     } else {
         // wait on fences so tasks don't overlap next frame
         context->waitOnFences();
@@ -149,10 +152,14 @@
             mUpdateTargetWorkDuration(targetWorkDuration);
         }
         int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
-        if (frameDuration > kSanityCheckLowerBound && frameDuration < kSanityCheckUpperBound) {
-            mReportActualWorkDuration(frameDuration);
+        int64_t actualDuration = frameDuration -
+                                 (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
+                                 dequeueBufferDuration;
+        if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) {
+            mReportActualWorkDuration(actualDuration);
         }
     }
+    mLastDequeueBufferDuration = dequeueBufferDuration;
 }
 
 bool DrawFrameTask::syncFrameState(TreeInfo& info) {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 3bb574a..2455ea8 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -110,6 +110,7 @@
     std::function<void(int64_t)> mFrameCallback;
     std::function<void(int64_t)> mFrameCompleteCallback;
 
+    nsecs_t mLastDequeueBufferDuration = 0;
     nsecs_t mLastTargetWorkDuration = 0;
     std::function<void(int64_t)> mUpdateTargetWorkDuration;
     std::function<void(int64_t)> mReportActualWorkDuration;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 1b4b4b9..ad325cf 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -249,10 +249,10 @@
     });
 }
 
-void RenderProxy::dumpGraphicsMemory(int fd) {
+void RenderProxy::dumpGraphicsMemory(int fd, bool includeProfileData) {
     if (RenderThread::hasInstance()) {
         auto& thread = RenderThread::getInstance();
-        thread.queue().runSync([&]() { thread.dumpGraphicsMemory(fd); });
+        thread.queue().runSync([&]() { thread.dumpGraphicsMemory(fd, includeProfileData); });
     }
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 288f555..662b445 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -109,7 +109,7 @@
     // Not exported, only used for testing
     void resetProfileInfo();
     uint32_t frameTimePercentile(int p);
-    static void dumpGraphicsMemory(int fd);
+    static void dumpGraphicsMemory(int fd, bool includeProfileData = true);
 
     static void rotateProcessStatsBuffer();
     static void setProcessStatsBuffer(int fd);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 3421e01..308352d 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -302,30 +302,25 @@
     return *mVkManager.get();
 }
 
-void RenderThread::dumpGraphicsMemory(int fd) {
-    globalProfileData()->dump(fd);
-
-    String8 cachesOutput;
-    String8 pipeline;
-    auto renderType = Properties::getRenderPipelineType();
-    switch (renderType) {
-        case RenderPipelineType::SkiaGL: {
-            mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
-            pipeline.appendFormat("Skia (OpenGL)");
-            break;
-        }
-        case RenderPipelineType::SkiaVulkan: {
-            mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
-            pipeline.appendFormat("Skia (Vulkan)");
-            break;
-        }
+static const char* pipelineToString() {
+    switch (auto renderType = Properties::getRenderPipelineType()) {
+        case RenderPipelineType::SkiaGL:
+            return "Skia (OpenGL)";
+        case RenderPipelineType::SkiaVulkan:
+            return "Skia (Vulkan)";
         default:
             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
-            break;
+    }
+}
+
+void RenderThread::dumpGraphicsMemory(int fd, bool includeProfileData) {
+    if (includeProfileData) {
+        globalProfileData()->dump(fd);
     }
 
-    dprintf(fd, "\n%s\n", cachesOutput.string());
-    dprintf(fd, "\nPipeline=%s\n", pipeline.string());
+    String8 cachesOutput;
+    mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
+    dprintf(fd, "\nPipeline=%s\n%s\n", pipelineToString(), cachesOutput.string());
 }
 
 Readback& RenderThread::readback() {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index cd9b923..afd5750 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -150,7 +150,7 @@
     VulkanManager& vulkanManager();
 
     sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap);
-    void dumpGraphicsMemory(int fd);
+    void dumpGraphicsMemory(int fd, bool includeProfileData);
 
     void requireGlContext();
     void requireVkContext();
diff --git a/libs/hwui/tests/common/TestScene.cpp b/libs/hwui/tests/common/TestScene.cpp
index 02bcd47..2c532b0 100644
--- a/libs/hwui/tests/common/TestScene.cpp
+++ b/libs/hwui/tests/common/TestScene.cpp
@@ -22,8 +22,9 @@
 
 // Not a static global because we need to force the map to be constructed
 // before we try to add things to it.
-std::unordered_map<std::string, TestScene::Info>& TestScene::testMap() {
-    static std::unordered_map<std::string, TestScene::Info> testMap;
+// std::map because tests sorted by name is a prettier output
+std::map<std::string, TestScene::Info>& TestScene::testMap() {
+    static std::map<std::string, TestScene::Info> testMap;
     return testMap;
 }
 
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index 91022cf..781884a 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -19,8 +19,8 @@
 #include <gui/Surface.h>
 #include <utils/StrongPointer.h>
 
+#include <map>
 #include <string>
-#include <unordered_map>
 
 namespace android {
 
@@ -35,9 +35,11 @@
 class TestScene {
 public:
     struct Options {
-        int count = 0;
+        int frameCount = 150;
+        int repeatCount = 1;
         int reportFrametimeWeight = 0;
         bool renderOffscreen = true;
+        bool reportGpuMemoryUsage = false;
     };
 
     template <class T>
@@ -67,7 +69,7 @@
     virtual void createContent(int width, int height, Canvas& renderer) = 0;
     virtual void doFrame(int frameNr) = 0;
 
-    static std::unordered_map<std::string, Info>& testMap();
+    static std::map<std::string, Info>& testMap();
     static void registerScene(const Info& info);
 
     sp<Surface> renderTarget;
diff --git a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
new file mode 100644
index 0000000..964b8bf
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ */
+
+#include <SkFont.h>
+#include <cstdio>
+#include "TestSceneBase.h"
+#include "hwui/Paint.h"
+#include "tests/common/TestUtils.h"
+
+class StretchyListViewAnimation;
+class StretchyListViewHolePunch;
+class StretchyLinearListView;
+class StretchyLinearListViewHolePunch;
+
+static TestScene::Registrar _StretchyListViewAnimation(TestScene::Info{
+        "stretchylistview",
+        "A mock ListView of scrolling content that's stretching. Doesn't re-bind/re-record views "
+        "as they are recycled, so won't upload much content (either glyphs, or bitmaps).",
+        TestScene::simpleCreateScene<StretchyListViewAnimation>});
+
+static TestScene::Registrar _StretchyListViewHolePunch(TestScene::Info{
+        "stretchylistview_holepunch",
+        "A mock ListView of scrolling content that's stretching. Includes a hole punch",
+        TestScene::simpleCreateScene<StretchyListViewHolePunch>});
+
+static TestScene::Registrar _StretchyLinearListView(TestScene::Info{
+        "stretchylistview_linear",
+        "A mock ListView of scrolling content that's stretching using a linear stretch effect.",
+        TestScene::simpleCreateScene<StretchyLinearListView>});
+
+static TestScene::Registrar _StretchyLinearListViewHolePunch(TestScene::Info{
+        "stretchylistview_linear_holepunch",
+        "A mock ListView of scrolling content that's stretching using a linear stretch effect. "
+        "Includes a hole punch",
+        TestScene::simpleCreateScene<StretchyLinearListViewHolePunch>});
+
+class StretchyListViewAnimation : public TestScene {
+protected:
+    virtual StretchEffectBehavior stretchBehavior() { return StretchEffectBehavior::Shader; }
+    virtual bool haveHolePunch() { return false; }
+
+private:
+    int mItemHeight;
+    int mItemSpacing;
+    int mItemWidth;
+    int mItemLeft;
+    sp<RenderNode> mListView;
+    std::vector<sp<RenderNode> > mListItems;
+
+    sk_sp<Bitmap> createRandomCharIcon(int cardHeight) {
+        SkBitmap skBitmap;
+        int size = cardHeight - (dp(10) * 2);
+        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(size, size, &skBitmap));
+        SkCanvas canvas(skBitmap);
+        canvas.clear(0);
+
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        SkColor randomColor = BrightColors[rand() % BrightColorsCount];
+        paint.setColor(randomColor);
+        canvas.drawCircle(size / 2, size / 2, size / 2, paint);
+
+        bool bgDark =
+                SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor) <
+                128 * 3;
+        paint.setColor(bgDark ? Color::White : Color::Grey_700);
+
+        SkFont font;
+        font.setSize(size / 2);
+        char charToShow = 'A' + (rand() % 26);
+        const SkPoint pos = {SkIntToScalar(size / 2),
+                             /*approximate centering*/ SkFloatToScalar(size * 0.7f)};
+        canvas.drawSimpleText(&charToShow, 1, SkTextEncoding::kUTF8, pos.fX, pos.fY, font, paint);
+        return bitmap;
+    }
+
+    static sk_sp<Bitmap> createBoxBitmap(bool filled) {
+        int size = dp(20);
+        int stroke = dp(2);
+        SkBitmap skBitmap;
+        auto bitmap = TestUtils::createBitmap(size, size, &skBitmap);
+        SkCanvas canvas(skBitmap);
+        canvas.clear(Color::Transparent);
+
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setColor(filled ? Color::Yellow_500 : Color::Grey_700);
+        paint.setStyle(filled ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style);
+        paint.setStrokeWidth(stroke);
+        canvas.drawRect(SkRect::MakeLTRB(stroke, stroke, size - stroke, size - stroke), paint);
+        return bitmap;
+    }
+
+    void createListItem(RenderProperties& props, Canvas& canvas, int cardId, int itemWidth,
+                        int itemHeight) {
+        static sk_sp<Bitmap> filledBox(createBoxBitmap(true));
+        static sk_sp<Bitmap> strokedBox(createBoxBitmap(false));
+        const bool addHolePunch = cardId == 2 && haveHolePunch();
+        // TODO: switch to using round rect clipping, once merging correctly handles that
+        Paint roundRectPaint;
+        roundRectPaint.setAntiAlias(true);
+        roundRectPaint.setColor(Color::White);
+        if (addHolePunch) {
+            // Punch a hole but then cover it up, we don't want to actually see it
+            canvas.punchHole(SkRRect::MakeRect(SkRect::MakeWH(itemWidth, itemHeight)));
+        }
+        canvas.drawRoundRect(0, 0, itemWidth, itemHeight, dp(6), dp(6), roundRectPaint);
+
+        Paint textPaint;
+        textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500);
+        textPaint.getSkFont().setSize(dp(20));
+        textPaint.setAntiAlias(true);
+        char buf[256];
+        snprintf(buf, sizeof(buf), "This card is #%d", cardId);
+        TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, itemHeight, dp(25));
+        textPaint.getSkFont().setSize(dp(15));
+        if (addHolePunch) {
+            TestUtils::drawUtf8ToCanvas(&canvas, "I have a hole punch", textPaint, itemHeight,
+                                        dp(45));
+        } else {
+            TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint,
+                                        itemHeight, dp(45));
+        }
+
+        auto randomIcon = createRandomCharIcon(itemHeight);
+        canvas.drawBitmap(*randomIcon, dp(10), dp(10), nullptr);
+
+        auto box = rand() % 2 ? filledBox : strokedBox;
+        canvas.drawBitmap(*box, itemWidth - dp(10) - box->width(), dp(10), nullptr);
+    }
+
+    void createContent(int width, int height, Canvas& canvas) override {
+        srand(0);
+        mItemHeight = dp(60);
+        mItemSpacing = dp(16);
+        mItemWidth = std::min((height - mItemSpacing * 2), (int)dp(300));
+        mItemLeft = (width - mItemWidth) / 2;
+        int heightWithSpacing = mItemHeight + mItemSpacing;
+        for (int y = 0; y < height + (heightWithSpacing - 1); y += heightWithSpacing) {
+            int id = mListItems.size();
+            auto node = TestUtils::createNode(mItemLeft, y, mItemLeft + mItemWidth, y + mItemHeight,
+                                              [this, id](RenderProperties& props, Canvas& canvas) {
+                                                  createListItem(props, canvas, id, mItemWidth,
+                                                                 mItemHeight);
+                                              });
+            mListItems.push_back(node);
+        }
+        mListView = TestUtils::createNode(0, 0, width, height,
+                                          [this](RenderProperties& props, Canvas& canvas) {
+                                              for (size_t ci = 0; ci < mListItems.size(); ci++) {
+                                                  canvas.drawRenderNode(mListItems[ci].get());
+                                              }
+                                          });
+
+        canvas.drawColor(Color::Grey_500, SkBlendMode::kSrcOver);
+        canvas.drawRenderNode(mListView.get());
+    }
+
+    void doFrame(int frameNr) override {
+        if (frameNr == 0) {
+            Properties::stretchEffectBehavior = stretchBehavior();
+        }
+        auto& props = mListView->mutateStagingProperties();
+        auto& stretch = props.mutateLayerProperties().mutableStretchEffect();
+        stretch.setEmpty();
+        frameNr = frameNr % 150;
+        // Animate from 0f to .1f
+        const float sY = (frameNr > 75 ? 150 - frameNr : frameNr) / 1500.f;
+        stretch.mergeWith({{.fX = 0, .fY = sY},
+                           static_cast<float>(props.getWidth()),
+                           static_cast<float>(props.getHeight())});
+        mListView->setPropertyFieldsDirty(RenderNode::GENERIC);
+    }
+};
+
+class StretchyListViewHolePunch : public StretchyListViewAnimation {
+    bool haveHolePunch() override { return true; }
+};
+
+class StretchyLinearListView : public StretchyListViewAnimation {
+    StretchEffectBehavior stretchBehavior() override { return StretchEffectBehavior::LinearScale; }
+};
+
+class StretchyLinearListViewHolePunch : public StretchyListViewAnimation {
+    StretchEffectBehavior stretchBehavior() override { return StretchEffectBehavior::LinearScale; }
+    bool haveHolePunch() override { return true; }
+};
\ No newline at end of file
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 13ac367..9d3b732 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -62,53 +62,23 @@
     T mAverage;
 };
 
+using BenchmarkResults = std::vector<benchmark::BenchmarkReporter::Run>;
+
 void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options& opts,
-                           benchmark::BenchmarkReporter* reporter, RenderProxy* proxy,
-                           double durationInS) {
-    using namespace benchmark;
-
-    struct ReportInfo {
-        int percentile;
-        const char* suffix;
-    };
-
-    static std::array<ReportInfo, 4> REPORTS = {
-            ReportInfo{50, "_50th"}, ReportInfo{90, "_90th"}, ReportInfo{95, "_95th"},
-            ReportInfo{99, "_99th"},
-    };
-
-    // Although a vector is used, it must stay with only a single element
-    // otherwise the BenchmarkReporter will automatically compute
-    // mean and stddev which doesn't make sense for our usage
-    std::vector<BenchmarkReporter::Run> reports;
-    BenchmarkReporter::Run report;
+                           double durationInS, int repetationIndex, BenchmarkResults* reports) {
+    benchmark::BenchmarkReporter::Run report;
+    report.repetitions = opts.repeatCount;
+    report.repetition_index = repetationIndex;
     report.run_name.function_name = info.name;
-    report.iterations = static_cast<int64_t>(opts.count);
+    report.iterations = static_cast<int64_t>(opts.frameCount);
     report.real_accumulated_time = durationInS;
     report.cpu_accumulated_time = durationInS;
-    report.counters["items_per_second"] = opts.count / durationInS;
-    reports.push_back(report);
-    reporter->ReportRuns(reports);
-
-    // Pretend the percentiles are single-iteration runs of the test
-    // If rendering offscreen skip this as it's fps that's more interesting
-    // in that test case than percentiles.
-    if (!opts.renderOffscreen) {
-        for (auto& ri : REPORTS) {
-            reports[0].run_name.function_name = info.name;
-            reports[0].run_name.function_name += ri.suffix;
-            durationInS = proxy->frameTimePercentile(ri.percentile) / 1000.0;
-            reports[0].real_accumulated_time = durationInS;
-            reports[0].cpu_accumulated_time = durationInS;
-            reports[0].iterations = 1;
-            reports[0].counters["items_per_second"] = 0;
-            reporter->ReportRuns(reports);
-        }
-    }
+    report.counters["items_per_second"] = opts.frameCount / durationInS;
+    reports->push_back(report);
 }
 
-void run(const TestScene::Info& info, const TestScene::Options& opts,
-         benchmark::BenchmarkReporter* reporter) {
+static void doRun(const TestScene::Info& info, const TestScene::Options& opts, int repetitionIndex,
+                  BenchmarkResults* reports) {
     Properties::forceDrawFrame = true;
     TestContext testContext;
     testContext.setRenderOffscreen(opts.renderOffscreen);
@@ -158,7 +128,7 @@
     ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
 
     nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
-    for (int i = 0; i < opts.count; i++) {
+    for (int i = 0; i < opts.frameCount; i++) {
         testContext.waitForVsync();
         nsecs_t vsync = systemTime(SYSTEM_TIME_MONOTONIC);
         {
@@ -182,9 +152,32 @@
     proxy->fence();
     nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    if (reporter) {
-        outputBenchmarkReport(info, opts, reporter, proxy.get(), (end - start) / (double)s2ns(1));
+    if (reports) {
+        outputBenchmarkReport(info, opts, (end - start) / (double)s2ns(1), repetitionIndex,
+                              reports);
     } else {
         proxy->dumpProfileInfo(STDOUT_FILENO, DumpFlags::JankStats);
     }
 }
+
+void run(const TestScene::Info& info, const TestScene::Options& opts,
+         benchmark::BenchmarkReporter* reporter) {
+    if (opts.reportGpuMemoryUsage) {
+        // If we're reporting GPU memory usage we need to first start with a clean slate
+        // All repetitions of the same test will share a single memory usage report
+        RenderProxy::trimMemory(100);
+    }
+    BenchmarkResults results;
+    for (int i = 0; i < opts.repeatCount; i++) {
+        doRun(info, opts, i, reporter ? &results : nullptr);
+    }
+    if (reporter) {
+        reporter->ReportRuns(results);
+        if (results.size() > 1) {
+            // TODO: Report summary
+        }
+    }
+    if (opts.reportGpuMemoryUsage) {
+        RenderProxy::dumpGraphicsMemory(STDOUT_FILENO, false);
+    }
+}
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 174a140..e9e962a 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -23,6 +23,7 @@
 #include "renderthread/RenderProxy.h"
 
 #include <benchmark/benchmark.h>
+#include <fnmatch.h>
 #include <getopt.h>
 #include <pthread.h>
 #include <stdio.h>
@@ -40,9 +41,9 @@
 using namespace android::uirenderer;
 using namespace android::uirenderer::test;
 
-static int gRepeatCount = 1;
 static std::vector<TestScene::Info> gRunTests;
 static TestScene::Options gOpts;
+static bool gRunLeakCheck = true;
 std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
 
 void run(const TestScene::Info& info, const TestScene::Options& opts,
@@ -69,6 +70,8 @@
                        are offscreen rendered
   --benchmark_format   Set output format. Possible values are tabular, json, csv
   --renderer=TYPE      Sets the render pipeline to use. May be skiagl or skiavk
+  --skip-leak-check    Skips the memory leak check
+  --report-gpu-memory  Dumps the GPU memory usage after each test run
 )");
 }
 
@@ -170,6 +173,8 @@
     Onscreen,
     Offscreen,
     Renderer,
+    SkipLeakCheck,
+    ReportGpuMemory,
 };
 }
 
@@ -185,6 +190,8 @@
         {"onscreen", no_argument, nullptr, LongOpts::Onscreen},
         {"offscreen", no_argument, nullptr, LongOpts::Offscreen},
         {"renderer", required_argument, nullptr, LongOpts::Renderer},
+        {"skip-leak-check", no_argument, nullptr, LongOpts::SkipLeakCheck},
+        {"report-gpu-memory", no_argument, nullptr, LongOpts::ReportGpuMemory},
         {0, 0, 0, 0}};
 
 static const char* SHORT_OPTIONS = "c:r:h";
@@ -214,20 +221,20 @@
                 break;
 
             case 'c':
-                gOpts.count = atoi(optarg);
-                if (!gOpts.count) {
+                gOpts.frameCount = atoi(optarg);
+                if (!gOpts.frameCount) {
                     fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
                     error = true;
                 }
                 break;
 
             case 'r':
-                gRepeatCount = atoi(optarg);
-                if (!gRepeatCount) {
+                gOpts.repeatCount = atoi(optarg);
+                if (!gOpts.repeatCount) {
                     fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
                     error = true;
                 } else {
-                    gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
+                    gOpts.repeatCount = (gOpts.repeatCount > 0 ? gOpts.repeatCount : INT_MAX);
                 }
                 break;
 
@@ -283,6 +290,14 @@
                 gOpts.renderOffscreen = true;
                 break;
 
+            case LongOpts::SkipLeakCheck:
+                gRunLeakCheck = false;
+                break;
+
+            case LongOpts::ReportGpuMemory:
+                gOpts.reportGpuMemoryUsage = true;
+                break;
+
             case 'h':
                 printHelp();
                 exit(EXIT_SUCCESS);
@@ -306,12 +321,21 @@
     if (optind < argc) {
         do {
             const char* test = argv[optind++];
-            auto pos = TestScene::testMap().find(test);
-            if (pos == TestScene::testMap().end()) {
-                fprintf(stderr, "Unknown test '%s'\n", test);
-                exit(EXIT_FAILURE);
+            if (strchr(test, '*')) {
+                // Glob match
+                for (auto& iter : TestScene::testMap()) {
+                    if (!fnmatch(test, iter.first.c_str(), 0)) {
+                        gRunTests.push_back(iter.second);
+                    }
+                }
             } else {
-                gRunTests.push_back(pos->second);
+                auto pos = TestScene::testMap().find(test);
+                if (pos == TestScene::testMap().end()) {
+                    fprintf(stderr, "Unknown test '%s'\n", test);
+                    exit(EXIT_FAILURE);
+                } else {
+                    gRunTests.push_back(pos->second);
+                }
             }
         } while (optind < argc);
     } else {
@@ -322,9 +346,6 @@
 }
 
 int main(int argc, char* argv[]) {
-    // set defaults
-    gOpts.count = 150;
-
     Typeface::setRobotoTypefaceForTest();
 
     parseOptions(argc, argv);
@@ -345,10 +366,8 @@
         gBenchmarkReporter->ReportContext(context);
     }
 
-    for (int i = 0; i < gRepeatCount; i++) {
-        for (auto&& test : gRunTests) {
-            run(test, gOpts, gBenchmarkReporter.get());
-        }
+    for (auto&& test : gRunTests) {
+        run(test, gOpts, gBenchmarkReporter.get());
     }
 
     if (gBenchmarkReporter) {
@@ -358,6 +377,8 @@
     renderthread::RenderProxy::trimMemory(100);
     HardwareBitmapUploader::terminate();
 
-    LeakChecker::checkForLeaks();
+    if (gRunLeakCheck) {
+        LeakChecker::checkForLeaks();
+    }
     return 0;
 }
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 8fee768..c8412f2 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -518,13 +518,13 @@
      * @hide
      */
     // never unhide
-    public static final int SAMPLE_RATE_HZ_MIN = 4000;
+    public static final int SAMPLE_RATE_HZ_MIN = AudioSystem.SAMPLE_RATE_HZ_MIN;
     /** Maximum value for sample rate,
      *  assuming AudioTrack and AudioRecord share the same limitations.
      * @hide
      */
     // never unhide
-    public static final int SAMPLE_RATE_HZ_MAX = 192000;
+    public static final int SAMPLE_RATE_HZ_MAX = AudioSystem.SAMPLE_RATE_HZ_MAX;
     /** Sample rate will be a route-dependent value.
      * For AudioTrack, it is usually the sink sample rate,
      * and for AudioRecord it is usually the source sample rate.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f2f9a26..14d4937 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -7068,15 +7068,7 @@
 
     /**
      * Set a certain surround format as enabled or not.
-     * @param audioFormat a surround format, the value is one of
-     *        {@link AudioFormat#ENCODING_AC3}, {@link AudioFormat#ENCODING_E_AC3},
-     *        {@link AudioFormat#ENCODING_DTS}, {@link AudioFormat#ENCODING_DTS_HD},
-     *        {@link AudioFormat#ENCODING_AAC_LC}, {@link AudioFormat#ENCODING_DOLBY_TRUEHD},
-     *        {@link AudioFormat#ENCODING_E_AC3_JOC}. Once {@link AudioFormat#ENCODING_AAC_LC} is
-     *        set as enabled, {@link AudioFormat#ENCODING_AAC_LC},
-     *        {@link AudioFormat#ENCODING_AAC_HE_V1}, {@link AudioFormat#ENCODING_AAC_HE_V2},
-     *        {@link AudioFormat#ENCODING_AAC_ELD}, {@link AudioFormat#ENCODING_AAC_XHE} are
-     *        all enabled.
+     *
      * @param enabled the required surround format state, true for enabled, false for disabled
      * @return true if successful, otherwise false
      */
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index ce9d7e3..5f6fc17 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -105,11 +105,34 @@
      */
     public static final int NUM_STREAMS = 5;
 
-    /** Maximum value for AudioTrack channel count
-     * @hide public for MediaCode only, do not un-hide or change to a numeric literal
+    /*
+     * Framework static final constants that are primitives or Strings
+     * accessed by CTS tests or internal applications must be set from methods
+     * (or in a static block) to prevent Java compile-time replacement.
+     * We set them from methods so they are read from the device framework.
+     * Do not un-hide or change to a numeric literal.
      */
-    public static final int OUT_CHANNEL_COUNT_MAX = native_get_FCC_8();
-    private static native int native_get_FCC_8();
+
+    /** Maximum value for AudioTrack channel count
+     * @hide
+     */
+    public static final int OUT_CHANNEL_COUNT_MAX = native_getMaxChannelCount();
+    private static native int native_getMaxChannelCount();
+
+    /** Maximum value for sample rate, used by AudioFormat.
+     * @hide
+     */
+    public static final int SAMPLE_RATE_HZ_MAX = native_getMaxSampleRate();
+    private static native int native_getMaxSampleRate();
+
+    /** Minimum value for sample rate, used by AudioFormat.
+     * @hide
+     */
+    public static final int SAMPLE_RATE_HZ_MIN = native_getMinSampleRate();
+    private static native int native_getMinSampleRate();
+
+    /** @hide */
+    public static final int FCC_24 = 24; // fixed channel count 24; do not change.
 
     // Expose only the getter method publicly so we can change it in the future
     private static final int NUM_STREAM_TYPES = 12;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b2b2f8e..23d9532 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1720,9 +1720,10 @@
                 mChannelCount = 0;
                 break; // channel index configuration only
             }
-            if (!isMultichannelConfigSupported(channelConfig)) {
-                // input channel configuration features unsupported channels
-                throw new IllegalArgumentException("Unsupported channel configuration.");
+            if (!isMultichannelConfigSupported(channelConfig, audioFormat)) {
+                throw new IllegalArgumentException(
+                        "Unsupported channel mask configuration " + channelConfig
+                        + " for encoding " + audioFormat);
             }
             mChannelMask = channelConfig;
             mChannelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
@@ -1730,13 +1731,17 @@
         // check the channel index configuration (if present)
         mChannelIndexMask = channelIndexMask;
         if (mChannelIndexMask != 0) {
-            // restrictive: indexMask could allow up to AUDIO_CHANNEL_BITS_LOG2
-            final int indexMask = (1 << AudioSystem.OUT_CHANNEL_COUNT_MAX) - 1;
-            if ((channelIndexMask & ~indexMask) != 0) {
-                throw new IllegalArgumentException("Unsupported channel index configuration "
-                        + channelIndexMask);
+            // As of S, we accept up to 24 channel index mask.
+            final int fullIndexMask = (1 << AudioSystem.FCC_24) - 1;
+            final int channelIndexCount = Integer.bitCount(channelIndexMask);
+            final boolean accepted = (channelIndexMask & ~fullIndexMask) == 0
+                    && (!AudioFormat.isEncodingLinearFrames(audioFormat)  // compressed OK
+                            || channelIndexCount <= AudioSystem.OUT_CHANNEL_COUNT_MAX); // PCM
+            if (!accepted) {
+                throw new IllegalArgumentException(
+                        "Unsupported channel index mask configuration " + channelIndexMask
+                        + " for encoding " + audioFormat);
             }
-            int channelIndexCount = Integer.bitCount(channelIndexMask);
             if (mChannelCount == 0) {
                  mChannelCount = channelIndexCount;
             } else if (mChannelCount != channelIndexCount) {
@@ -1789,16 +1794,19 @@
      * @param channelConfig the mask to validate
      * @return false if the AudioTrack can't be used with such a mask
      */
-    private static boolean isMultichannelConfigSupported(int channelConfig) {
+    private static boolean isMultichannelConfigSupported(int channelConfig, int encoding) {
         // check for unsupported channels
         if ((channelConfig & SUPPORTED_OUT_CHANNELS) != channelConfig) {
             loge("Channel configuration features unsupported channels");
             return false;
         }
         final int channelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
-        if (channelCount > AudioSystem.OUT_CHANNEL_COUNT_MAX) {
-            loge("Channel configuration contains too many channels " +
-                    channelCount + ">" + AudioSystem.OUT_CHANNEL_COUNT_MAX);
+        final int channelCountLimit = AudioFormat.isEncodingLinearFrames(encoding)
+                ? AudioSystem.OUT_CHANNEL_COUNT_MAX  // PCM limited to OUT_CHANNEL_COUNT_MAX
+                : AudioSystem.FCC_24;                // Compressed limited to 24 channels
+        if (channelCount > channelCountLimit) {
+            loge("Channel configuration contains too many channels for encoding "
+                    + encoding + "(" + channelCount + " > " + channelCountLimit + ")");
             return false;
         }
         // check for unsupported multichannel combinations:
@@ -2310,7 +2318,7 @@
             channelCount = 2;
             break;
         default:
-            if (!isMultichannelConfigSupported(channelConfig)) {
+            if (!isMultichannelConfigSupported(channelConfig, audioFormat)) {
                 loge("getMinBufferSize(): Invalid channel configuration.");
                 return ERROR_BAD_VALUE;
             } else {
diff --git a/media/java/android/media/metrics/PlaybackErrorEvent.java b/media/java/android/media/metrics/PlaybackErrorEvent.java
index d155576..184b359 100644
--- a/media/java/android/media/metrics/PlaybackErrorEvent.java
+++ b/media/java/android/media/metrics/PlaybackErrorEvent.java
@@ -39,71 +39,95 @@
     /** Error code for runtime errors */
     public static final int ERROR_RUNTIME = 2;
 
-    /** No network */
-    public static final int ERROR_NETWORK_OFFLINE = 3;
-    /** Connection opening error */
-    public static final int ERROR_NETWORK_CONNECT = 4;
-    /** Bad HTTP status code */
-    public static final int ERROR_NETWORK_BAD_STATUS = 5;
-    /** DNS resolution error */
-    public static final int ERROR_NETWORK_DNS = 6;
-    /** Network socket timeout */
-    public static final int ERROR_NETWORK_TIMEOUT = 7;
-    /** Connection closed */
-    public static final int ERROR_NETWORK_CLOSED = 8;
-    /** Other network errors */
-    public static final int ERROR_NETWORK_OTHER = 9;
-
-    /** Manifest parsing error */
-    public static final int ERROR_MEDIA_MANIFEST = 10;
+    /** Error code for lack of network connectivity while trying to access a network resource */
+    public static final int ERROR_IO_NETWORK_UNAVAILABLE = 3;
+    /** Error code for a failure while establishing a network connection */
+    public static final int ERROR_IO_NETWORK_CONNECTION_FAILED = 4;
+    /** Error code for an HTTP server returning an unexpected HTTP response status code */
+    public static final int ERROR_IO_BAD_HTTP_STATUS = 5;
+    /** Error code for failing to resolve a hostname */
+    public static final int ERROR_IO_DNS_FAILED = 6;
     /**
-     * Media bitstream (audio, video, text, metadata) parsing error, either malformed or
-     * unsupported.
+     * Error code for a network timeout, meaning the server is taking too long to fulfill
+     * a request
      */
-    public static final int ERROR_MEDIA_PARSER = 11;
-    /** Other media errors */
-    public static final int ERROR_MEDIA_OTHER = 12;
+    public static final int ERROR_IO_CONNECTION_TIMEOUT = 7;
+    /** Error code for an existing network connection being unexpectedly closed */
+    public static final int ERROR_IO_CONNECTION_CLOSED = 8;
+    /** Error code for other Input/Output errors */
+    public static final int ERROR_IO_OTHER = 9;
 
-    /** Codec initialization failed */
-    public static final int ERROR_DECODER_INIT = 13;
-    /** Decoding failed */
-    public static final int ERROR_DECODER_DECODE = 14;
-    /** Out of memory */
-    public static final int ERROR_DECODER_OOM = 15;
-    /** Other decoder errors */
-    public static final int ERROR_DECODER_OTHER = 16;
+    /** Error code for a parsing error associated to a media manifest */
+    public static final int ERROR_PARSING_MANIFEST_MALFORMED = 10;
+    /** Error code for a parsing error associated to a media container format bitstream */
+    public static final int ERROR_PARSING_CONTAINER_MALFORMED = 11;
+    /** Error code for other media parsing errors */
+    public static final int ERROR_PARSING_OTHER = 12;
 
-    /** AudioTrack initialization failed */
-    public static final int ERROR_AUDIOTRACK_INIT = 17;
-    /** AudioTrack writing failed */
-    public static final int ERROR_AUDIOTRACK_WRITE = 18;
-    /** Other AudioTrack errors */
-    public static final int ERROR_AUDIOTRACK_OTHER = 19;
+    /** Error code for a decoder initialization failure */
+    public static final int ERROR_DECODER_INIT_FAILED = 13;
+    /** Error code for a failure while trying to decode media samples */
+    public static final int ERROR_DECODING_FAILED = 14;
+    /**
+     * Error code for trying to decode content whose format exceeds the capabilities of the device.
+     */
+    public static final int ERROR_DECODING_FORMAT_EXCEEDS_CAPABILITIES = 15;
+    /** Error code for other decoding errors */
+    public static final int ERROR_DECODING_OTHER = 16;
 
-    /** Exception in remote controller or player */
+    /** Error code for an AudioTrack initialization failure */
+    public static final int ERROR_AUDIO_TRACK_INIT_FAILED = 17;
+    /** Error code for an AudioTrack write operation failure */
+    public static final int ERROR_AUDIO_TRACK_WRITE_FAILED = 18;
+    /** Error code for other AudioTrack errors */
+    public static final int ERROR_AUDIO_TRACK_OTHER = 19;
+
+    /** Error code for an unidentified error in a remote controller or player */
     public static final int ERROR_PLAYER_REMOTE = 20;
-    /** Error when a Live playback falls behind the Live DVR window. */
+    /**
+     * Error code for the loading position falling behind the sliding window of available live
+     * content.
+     */
     public static final int ERROR_PLAYER_BEHIND_LIVE_WINDOW = 21;
-    /** Other player errors */
+    /** Error code for other player errors */
     public static final int ERROR_PLAYER_OTHER = 22;
 
-    /** Scheme unsupported by device */
-    public static final int ERROR_DRM_UNAVAILABLE = 23;
-    /** Provisioning failed */
+    /** Error code for a chosen DRM protection scheme not being supported by the device */
+    public static final int ERROR_DRM_SCHEME_UNSUPPORTED = 23;
+    /** Error code for a failure while provisioning the device */
     public static final int ERROR_DRM_PROVISIONING_FAILED = 24;
-    /** Failed to acquire license */
-    public static final int ERROR_DRM_LICENSE_ERROR = 25;
-    /** Operation prevented by license policy */
-    public static final int ERROR_DRM_DISALLOWED = 26;
-    /** Failure in the DRM system */
+    /** Error code for a failure while trying to obtain a license */
+    public static final int ERROR_DRM_LICENSE_ACQUISITION_FAILED = 25;
+    /** Error code an operation being disallowed by a license policy */
+    public static final int ERROR_DRM_DISALLOWED_OPERATION = 26;
+    /** Error code for an error in the DRM system */
     public static final int ERROR_DRM_SYSTEM_ERROR = 27;
-    /** Incompatible content */
+    /** Error code for attempting to play incompatible DRM-protected content */
     public static final int ERROR_DRM_CONTENT_ERROR = 28;
-    /** Device has been revoked */
-    public static final int ERROR_DRM_REVOKED = 29;
-    /** Other drm errors */
+    /** Error code for the device having revoked DRM privileges */
+    public static final int ERROR_DRM_DEVICE_REVOKED = 29;
+    /** Error code for other DRM errors */
     public static final int ERROR_DRM_OTHER = 30;
 
+    /** Error code for a non-existent file */
+    public static final int ERROR_IO_FILE_NOT_FOUND = 31;
+    /**
+     * Error code for lack of permission to perform an IO operation, for example, lack of permission
+     * to access internet or external storage.
+     */
+    public static final int ERROR_IO_NO_PERMISSION = 32;
+
+    /** Error code for an unsupported feature in a media manifest */
+    public static final int ERROR_PARSING_MANIFEST_UNSUPPORTED = 33;
+    /**
+     * Error code for attempting to extract a file with an unsupported media container format, or an
+     * unsupported media container feature
+     */
+    public static final int ERROR_PARSING_CONTAINER_UNSUPPORTED = 34;
+
+    /** Error code for trying to decode content whose format is not supported */
+    public static final int ERROR_DECODING_FORMAT_UNSUPPORTED = 35;
+
 
     private final @Nullable String mExceptionStack;
     private final int mErrorCode;
@@ -116,34 +140,39 @@
         ERROR_UNKNOWN,
         ERROR_OTHER,
         ERROR_RUNTIME,
-        ERROR_NETWORK_OFFLINE,
-        ERROR_NETWORK_CONNECT,
-        ERROR_NETWORK_BAD_STATUS,
-        ERROR_NETWORK_DNS,
-        ERROR_NETWORK_TIMEOUT,
-        ERROR_NETWORK_CLOSED,
-        ERROR_NETWORK_OTHER,
-        ERROR_MEDIA_MANIFEST,
-        ERROR_MEDIA_PARSER,
-        ERROR_MEDIA_OTHER,
-        ERROR_DECODER_INIT,
-        ERROR_DECODER_DECODE,
-        ERROR_DECODER_OOM,
-        ERROR_DECODER_OTHER,
-        ERROR_AUDIOTRACK_INIT,
-        ERROR_AUDIOTRACK_WRITE,
-        ERROR_AUDIOTRACK_OTHER,
+        ERROR_IO_NETWORK_UNAVAILABLE,
+        ERROR_IO_NETWORK_CONNECTION_FAILED,
+        ERROR_IO_BAD_HTTP_STATUS,
+        ERROR_IO_DNS_FAILED,
+        ERROR_IO_CONNECTION_TIMEOUT,
+        ERROR_IO_CONNECTION_CLOSED,
+        ERROR_IO_OTHER,
+        ERROR_PARSING_MANIFEST_MALFORMED,
+        ERROR_PARSING_CONTAINER_MALFORMED,
+        ERROR_PARSING_OTHER,
+        ERROR_DECODER_INIT_FAILED,
+        ERROR_DECODING_FAILED,
+        ERROR_DECODING_FORMAT_EXCEEDS_CAPABILITIES,
+        ERROR_DECODING_OTHER,
+        ERROR_AUDIO_TRACK_INIT_FAILED,
+        ERROR_AUDIO_TRACK_WRITE_FAILED,
+        ERROR_AUDIO_TRACK_OTHER,
         ERROR_PLAYER_REMOTE,
         ERROR_PLAYER_BEHIND_LIVE_WINDOW,
         ERROR_PLAYER_OTHER,
-        ERROR_DRM_UNAVAILABLE,
+        ERROR_DRM_SCHEME_UNSUPPORTED,
         ERROR_DRM_PROVISIONING_FAILED,
-        ERROR_DRM_LICENSE_ERROR,
-        ERROR_DRM_DISALLOWED,
+        ERROR_DRM_LICENSE_ACQUISITION_FAILED,
+        ERROR_DRM_DISALLOWED_OPERATION,
         ERROR_DRM_SYSTEM_ERROR,
         ERROR_DRM_CONTENT_ERROR,
-        ERROR_DRM_REVOKED,
+        ERROR_DRM_DEVICE_REVOKED,
         ERROR_DRM_OTHER,
+        ERROR_IO_FILE_NOT_FOUND,
+        ERROR_IO_NO_PERMISSION,
+        ERROR_PARSING_MANIFEST_UNSUPPORTED,
+        ERROR_PARSING_CONTAINER_UNSUPPORTED,
+        ERROR_DECODING_FORMAT_UNSUPPORTED,
     })
     @Retention(java.lang.annotation.RetentionPolicy.SOURCE)
     public @interface ErrorCode {}
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index a8c2ea5..93a5444 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -454,28 +454,7 @@
         sourceRect.makeInvalid();
     }
     transaction->setBufferCrop(surfaceControl, sourceRect);
-
-    int destW = destRect.width();
-    int destH = destRect.height();
-    if (destRect.left < 0) {
-        destRect.left = 0;
-        destRect.right = destW;
-    }
-    if (destRect.top < 0) {
-        destRect.top = 0;
-        destRect.bottom = destH;
-    }
-
-    if (!sourceRect.isEmpty()) {
-        float sx = destW / static_cast<float>(sourceRect.width());
-        float sy = destH / static_cast<float>(sourceRect.height());
-        transaction->setPosition(surfaceControl, destRect.left - (sourceRect.left * sx),
-                                 destRect.top - (sourceRect.top * sy));
-        transaction->setMatrix(surfaceControl, sx, 0, 0, sy);
-    } else {
-        transaction->setPosition(surfaceControl, destRect.left, destRect.top);
-    }
-
+    transaction->setDestinationFrame(surfaceControl, destRect);
     transaction->setTransform(surfaceControl, transform);
     bool transformToInverseDisplay = (NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY & transform) ==
             NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index 60b0f1e..9fe7929 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -329,7 +329,9 @@
                 static_cast<minikin::FamilyVariant>(matcher->mFamilyVariant),
                 1  /* maxRun */);
 
-    const std::shared_ptr<minikin::Font>& font = runs[0].fakedFont.font;
+    const std::shared_ptr<minikin::Font>& font =
+            fc->getBestFont(minikin::U16StringPiece(text, textLength), runs[0], matcher->mFontStyle)
+                    .font;
     std::unique_ptr<AFont> result = std::make_unique<AFont>();
     const android::MinikinFontSkia* minikinFontSkia =
             reinterpret_cast<android::MinikinFontSkia*>(font->typeface().get());
diff --git a/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp b/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
index 9bf910b..7478b3e 100644
--- a/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
+++ b/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
@@ -64,7 +64,7 @@
         filter_code,
     };
 
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
         jniThrowExceptionFmt(env, "java/net/SocketException",
                 "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
@@ -74,7 +74,7 @@
 static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
     int optval_ignored = 0;
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &optval_ignored, sizeof(optval_ignored)) !=
         0) {
         jniThrowExceptionFmt(env, "java/net/SocketException",
@@ -107,7 +107,7 @@
 
 static jint android_net_utils_bindSocketToNetworkHandle(JNIEnv *env, jobject thiz, jobject javaFd,
                                                   jlong netHandle) {
-    return android_setsocknetwork(netHandle, AFileDescriptor_getFD(env, javaFd));
+    return android_setsocknetwork(netHandle, AFileDescriptor_getFd(env, javaFd));
 }
 
 static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst)
@@ -156,7 +156,7 @@
 }
 
 static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     int rcode;
     uint8_t buf[MAXPACKETSIZE] = {0};
 
@@ -182,7 +182,7 @@
 }
 
 static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     android_res_cancel(fd);
     jniSetFileDescriptorOfFD(env, javaFd, -1);
 }
@@ -210,7 +210,7 @@
         return NULL;
     }
 
-    int fd = AFileDescriptor_getFD(env, javaFd);
+    int fd = AFileDescriptor_getFd(env, javaFd);
     struct tcp_repair_window trw = {};
     socklen_t size = sizeof(trw);
 
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 0bafd5b..3d6cc68 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -2461,7 +2461,8 @@
          * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
          * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
          * to be selected. This is logically different than
-         * {@code NetworkCapabilities.NET_CAPABILITY_*}.
+         * {@code NetworkCapabilities.NET_CAPABILITY_*}. Also note that multiple networks with the
+         * same transport type may be active concurrently.
          *
          * @param transportType the transport type to be added or removed.
          * @return this builder
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
index 784a747..ca69a28 100644
--- a/packages/CtsShim/apk/arm/CtsShim.apk
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
index 5b7bda4..d7cfb96 100644
--- a/packages/CtsShim/apk/arm/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
index 784a747..ca69a28 100644
--- a/packages/CtsShim/apk/x86/CtsShim.apk
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
index 780cb8a..84c3401 100644
--- a/packages/CtsShim/apk/x86/CtsShimPriv.apk
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 16a946d..f8cb5d3 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -561,7 +561,20 @@
                 break;
         }
 
-        Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail);
+        StringBuilder msg = new StringBuilder();
+        msg.append("status: " + statusString + ", cause: " + causeString);
+        if (status == STATUS_IN_PROGRESS) {
+            msg.append(
+                    String.format(
+                            ", partition name: %s, progress: %d/%d",
+                            mCurrentPartitionName,
+                            mCurrentPartitionInstalledSize,
+                            mCurrentPartitionSize));
+        }
+        if (detail != null) {
+            msg.append(", detail: " + detail);
+        }
+        Log.d(TAG, msg.toString());
 
         if (notifyOnNotificationBar) {
             mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail));
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 59ea9f0..f18d426 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -320,20 +320,21 @@
         }
     }
 
-    private void installScratch() throws IOException {
-        final long scratchSize = mDynSystem.suggestScratchSize();
+    private void installWritablePartition(final String partitionName, final long partitionSize)
+            throws IOException {
+        Log.d(TAG, "Creating writable partition: " + partitionName + ", size: " + partitionSize);
+
         Thread thread = new Thread() {
             @Override
             public void run() {
                 mInstallationSession =
-                        mDynSystem.createPartition("scratch", scratchSize, /* readOnly= */ false);
+                        mDynSystem.createPartition(
+                                partitionName, partitionSize, /* readOnly= */ false);
             }
         };
 
-        Log.d(TAG, "Creating partition: scratch, size = " + scratchSize);
         thread.start();
-
-        Progress progress = new Progress("scratch", scratchSize, mNumInstalledPartitions++);
+        Progress progress = new Progress(partitionName, partitionSize, mNumInstalledPartitions++);
 
         while (thread.isAlive()) {
             if (isCancelled()) {
@@ -356,53 +357,22 @@
 
         if (mInstallationSession == null) {
             throw new IOException(
-                    "Failed to start installation with requested size: " + scratchSize);
+                    "Failed to start installation with requested size: " + partitionSize);
         }
+
         // Reset installation session and verify that installation completes successfully.
         mInstallationSession = null;
         if (!mDynSystem.closePartition()) {
-            throw new IOException("Failed to complete partition installation: scratch");
+            throw new IOException("Failed to complete partition installation: " + partitionName);
         }
     }
 
+    private void installScratch() throws IOException {
+        installWritablePartition("scratch", mDynSystem.suggestScratchSize());
+    }
+
     private void installUserdata() throws IOException {
-        Thread thread = new Thread(() -> {
-            mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false);
-        });
-
-        Log.d(TAG, "Creating partition: userdata, size = " + mUserdataSize);
-        thread.start();
-
-        Progress progress = new Progress("userdata", mUserdataSize, mNumInstalledPartitions++);
-
-        while (thread.isAlive()) {
-            if (isCancelled()) {
-                return;
-            }
-
-            final long installedSize = mDynSystem.getInstallationProgress().bytes_processed;
-
-            if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
-                progress.installedSize = installedSize;
-                publishProgress(progress);
-            }
-
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException e) {
-                // Ignore the error.
-            }
-        }
-
-        if (mInstallationSession == null) {
-            throw new IOException(
-                    "Failed to start installation with requested size: " + mUserdataSize);
-        }
-        // Reset installation session and verify that installation completes successfully.
-        mInstallationSession = null;
-        if (!mDynSystem.closePartition()) {
-            throw new IOException("Failed to complete partition installation: userdata");
-        }
+        installWritablePartition("userdata", mUserdataSize);
     }
 
     private void installImages() throws IOException, ImageValidationException {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 0210079..9c6113c 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -86,7 +86,7 @@
     private int mOriginatingUid = PackageInstaller.SessionParams.UID_UNKNOWN;
     private String mOriginatingPackage; // The package name corresponding to #mOriginatingUid
 
-    private boolean localLOGV = false;
+    private final boolean mLocalLOGV = false;
     PackageManager mPm;
     IPackageManager mIpm;
     AppOpsManager mAppOpsManager;
@@ -104,7 +104,7 @@
     private List<UnknownSourcesListener> mActiveUnknownSourcesListeners = new ArrayList<>(1);
 
     // ApplicationInfo object primarily used for already existing applications
-    private ApplicationInfo mAppInfo = null;
+    private ApplicationInfo mAppInfo;
 
     // Buttons to indicate user acceptance
     private Button mOk;
@@ -154,6 +154,7 @@
      * @param id The dialog type to add
      */
     private void showDialogInner(int id) {
+        if (mLocalLOGV) Log.i(TAG, "showDialogInner(" + id + ")");
         DialogFragment currentDialog =
                 (DialogFragment) getFragmentManager().findFragmentByTag("dialog");
         if (currentDialog != null) {
@@ -174,6 +175,7 @@
      * @return The dialog
      */
     private DialogFragment createDialog(int id) {
+        if (mLocalLOGV) Log.i(TAG, "createDialog(" + id + ")");
         switch (id) {
             case DLG_PACKAGE_ERROR:
                 return SimpleErrorDialog.newInstance(R.string.Parse_error_dlg_text);
@@ -294,6 +296,7 @@
 
     @Override
     protected void onCreate(Bundle icicle) {
+        if (mLocalLOGV) Log.i(TAG, "creating for user " + getUserId());
         getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
 
         super.onCreate(null);
@@ -354,6 +357,8 @@
         }
 
         boolean wasSetUp = processPackageUri(packageUri);
+        if (mLocalLOGV) Log.i(TAG, "wasSetUp: " + wasSetUp);
+
         if (!wasSetUp) {
             return;
         }
@@ -363,6 +368,8 @@
     protected void onResume() {
         super.onResume();
 
+        if (mLocalLOGV) Log.i(TAG, "onResume(): mAppSnippet=" + mAppSnippet);
+
         if (mAppSnippet != null) {
             // load dummy layout with OK button disabled until we override this layout in
             // startInstallConfirm
@@ -443,15 +450,21 @@
         final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
                 UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
         if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
+            if (mLocalLOGV) Log.i(TAG, "install not allowed: " + UserManager.DISALLOW_INSTALL_APPS);
             showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
             return;
         } else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
+            if (mLocalLOGV) {
+                Log.i(TAG, "install not allowed by admin; showing "
+                        + Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
+            }
             startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
             finish();
             return;
         }
 
         if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
+            if (mLocalLOGV) Log.i(TAG, "install allowed");
             initiateInstall();
         } else {
             // Check for unknown sources restrictions.
@@ -462,6 +475,7 @@
             final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM
                     & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
             if (systemRestriction != 0) {
+                if (mLocalLOGV) Log.i(TAG, "Showing DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER");
                 showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
             } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
                 startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
@@ -475,13 +489,19 @@
     }
 
     private void startAdminSupportDetailsActivity(String restriction) {
+        if (mLocalLOGV) Log.i(TAG, "startAdminSupportDetailsActivity(): " + restriction);
+
         // If the given restriction is set by an admin, display information about the
         // admin enforcing the restriction for the affected user.
         final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
         final Intent showAdminSupportDetailsIntent = dpm.createAdminSupportIntent(restriction);
         if (showAdminSupportDetailsIntent != null) {
+            if (mLocalLOGV) Log.i(TAG, "starting " + showAdminSupportDetailsIntent);
             startActivity(showAdminSupportDetailsIntent);
+        } else {
+            if (mLocalLOGV) Log.w(TAG, "not intent for " + restriction);
         }
+
         finish();
     }
 
@@ -497,6 +517,7 @@
         final int appOpMode = mAppOpsManager.noteOpNoThrow(appOpCode, mOriginatingUid,
                 mOriginatingPackage, mCallingAttributionTag,
                 "Started package installation activity");
+        if (mLocalLOGV) Log.i(TAG, "handleUnknownSources(): appMode=" + appOpMode);
         switch (appOpMode) {
             case AppOpsManager.MODE_DEFAULT:
                 mAppOpsManager.setMode(appOpCode, mOriginatingUid,
@@ -527,6 +548,7 @@
         mPackageURI = packageUri;
 
         final String scheme = packageUri.getScheme();
+        if (mLocalLOGV) Log.i(TAG, "processPackageUri(): uri=" + packageUri + ", scheme=" + scheme);
 
         switch (scheme) {
             case SCHEME_PACKAGE: {
@@ -543,7 +565,9 @@
                     setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
                     return false;
                 }
-                mAppSnippet = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),
+                CharSequence label = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
+                if (mLocalLOGV) Log.i(TAG, "creating snippet for " + label);
+                mAppSnippet = new PackageUtil.AppSnippet(label,
                         mPm.getApplicationIcon(mPkgInfo.applicationInfo));
             } break;
 
@@ -559,6 +583,7 @@
                     setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
                     return false;
                 }
+                if (mLocalLOGV) Log.i(TAG, "creating snippet for local file " + sourceFile);
                 mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
             } break;
 
@@ -604,7 +629,7 @@
             newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
         }
         newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
-        if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
+        if (mLocalLOGV) Log.i(TAG, "downloaded app uri=" + mPackageURI);
         startActivity(newIntent);
         finish();
     }
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index d3a9f8f..f5570df 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -107,13 +107,18 @@
                 icon);
     }
 
-    static public class AppSnippet {
+    static final class AppSnippet {
         @NonNull public CharSequence label;
         @Nullable public Drawable icon;
         public AppSnippet(@NonNull CharSequence label, @Nullable Drawable icon) {
             this.label = label;
             this.icon = icon;
         }
+
+        @Override
+        public String toString() {
+            return "AppSnippet[" + label + (icon != null ? "(has" : "(no ") + " icon)]";
+        }
     }
 
     /**
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 69cee00..a65bf41 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -54,6 +54,7 @@
         "SettingsLibAppPreference",
         "SettingsLibSearchWidget",
         "SettingsLibSettingsSpinner",
+        "SettingsLibIllustrationPreference",
         "SettingsLibLayoutPreference",
         "SettingsLibMainSwitchPreference",
         "SettingsLibActionButtonsPreference",
diff --git a/packages/SettingsLib/IllustrationPreference/Android.bp b/packages/SettingsLib/IllustrationPreference/Android.bp
new file mode 100644
index 0000000..f8dd384
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/Android.bp
@@ -0,0 +1,23 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+    name: "SettingsLibIllustrationPreference",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    static_libs: [
+        "androidx.preference_preference",
+        "lottie",
+    ],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml b/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml
similarity index 65%
copy from packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
copy to packages/SettingsLib/IllustrationPreference/AndroidManifest.xml
index b646f0a..120b085 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
+++ b/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml
@@ -15,12 +15,9 @@
   limitations under the License.
   -->
 
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight">
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@color/state_off_color"/>
-            <corners android:radius="@dimen/switch_bar_radius"/>
-        </shape>
-    </item>
-</ripple>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/IllustrationPreference/res/drawable/ic_gesture_play_button.xml b/packages/SettingsLib/IllustrationPreference/res/drawable/ic_gesture_play_button.xml
new file mode 100644
index 0000000..55b3115
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/res/drawable/ic_gesture_play_button.xml
@@ -0,0 +1,24 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path android:fillColor="#FFFFFF" android:pathData="M24,24m-19,0a19,19 0,1 1,38 0a19,19 0,1 1,-38 0"/>
+    <path android:fillColor="#1A73E8" android:pathData="M20,33l12,-9l-12,-9z"/>
+    <path android:fillColor="#1A73E8" android:pathData="M24,4C12.96,4 4,12.96 4,24s8.96,20 20,20s20,-8.96 20,-20S35.04,4 24,4zM24,40c-8.82,0 -16,-7.18 -16,-16S15.18,8 24,8s16,7.18 16,16S32.82,40 24,40z"/>
+</vector>
diff --git a/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background.xml b/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background.xml
new file mode 100644
index 0000000..dd2fa5e
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/res/drawable/protection_background.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:top="@dimen/settingslib_illustration_padding"
+        android:left="@dimen/settingslib_illustration_padding"
+        android:right="@dimen/settingslib_illustration_padding"
+        android:bottom="@dimen/settingslib_illustration_padding">
+        <shape android:shape="rectangle">
+            <solid android:color="@color/settingslib_protection_color"/>
+            <corners android:radius="28dp"/>
+        </shape>
+    </item>
+</layer-list>
diff --git a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
new file mode 100644
index 0000000..2cbb888
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:background="?android:attr/colorBackground"
+    android:gravity="center"
+    android:orientation="horizontal">
+
+    <View
+        android:id="@+id/protection_layer"
+        android:layout_width="412dp"
+        android:layout_height="300dp"
+        android:layout_gravity="center"
+        android:padding="@dimen/settingslib_illustration_padding"
+        android:background="@drawable/protection_background"/>
+
+    <com.airbnb.lottie.LottieAnimationView
+        android:id="@+id/lottie_view"
+        android:layout_width="412dp"
+        android:layout_height="300dp"
+        android:layout_gravity="center"
+        android:padding="@dimen/settingslib_illustration_padding"
+        android:importantForAccessibility="no"/>
+
+    <ImageView
+        android:id="@+id/video_play_button"
+        android:layout_width="36dp"
+        android:layout_height="36dp"
+        android:layout_gravity="center"
+        android:visibility="gone"
+        android:src="@drawable/ic_gesture_play_button"/>
+
+</FrameLayout>
+
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml b/packages/SettingsLib/IllustrationPreference/res/values-night/colors.xml
similarity index 65%
copy from packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
copy to packages/SettingsLib/IllustrationPreference/res/values-night/colors.xml
index b646f0a..71b18a8 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values-night/colors.xml
@@ -15,12 +15,6 @@
   limitations under the License.
   -->
 
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight">
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@color/state_off_color"/>
-            <corners android:radius="@dimen/switch_bar_radius"/>
-        </shape>
-    </item>
-</ripple>
+<resources>
+    <color name="settingslib_protection_color">@android:color/black</color>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
similarity index 65%
copy from packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
copy to packages/SettingsLib/IllustrationPreference/res/values/colors.xml
index b646f0a..e53a43e 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
@@ -15,12 +15,6 @@
   limitations under the License.
   -->
 
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight">
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@color/state_off_color"/>
-            <corners android:radius="@dimen/switch_bar_radius"/>
-        </shape>
-    </item>
-</ripple>
+<resources>
+    <color name="settingslib_protection_color">@android:color/white</color>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml b/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml
similarity index 65%
copy from packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
copy to packages/SettingsLib/IllustrationPreference/res/values/dimens.xml
index b646f0a..79562b9 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values/dimens.xml
@@ -15,12 +15,7 @@
   limitations under the License.
   -->
 
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight">
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@color/state_off_color"/>
-            <corners android:radius="@dimen/switch_bar_radius"/>
-        </shape>
-    </item>
-</ripple>
+<resources>
+    <!-- Padding of illustration -->
+    <dimen name="settingslib_illustration_padding">16dp</dimen>
+</resources>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
new file mode 100644
index 0000000..90b8a32
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -0,0 +1,166 @@
+/*
+ * 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.settingslib.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.Preference.OnPreferenceClickListener;
+import androidx.preference.PreferenceViewHolder;
+
+import com.airbnb.lottie.LottieAnimationView;
+
+/**
+ * IllustrationPreference is a preference that can play lottie format animation
+ */
+public class IllustrationPreference extends Preference implements OnPreferenceClickListener {
+
+    static final String TAG = "IllustrationPreference";
+    private int mAnimationId;
+    private boolean mIsAnimating;
+    private ImageView mPlayButton;
+    private LottieAnimationView mIllustrationView;
+
+    public IllustrationPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context, attrs);
+    }
+
+    public IllustrationPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context, attrs);
+    }
+
+    public IllustrationPreference(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init(context, attrs);
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        if (mAnimationId == 0) {
+            Log.w(TAG, "Invalid illustration resource id.");
+            return;
+        }
+        mPlayButton = (ImageView) holder.findViewById(R.id.video_play_button);
+        mIllustrationView = (LottieAnimationView) holder.findViewById(R.id.lottie_view);
+        mIllustrationView.setAnimation(mAnimationId);
+        mIllustrationView.loop(true);
+        mIllustrationView.playAnimation();
+        updateAnimationStatus(mIsAnimating);
+        setOnPreferenceClickListener(this);
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        mIsAnimating = !isAnimating();
+        updateAnimationStatus(mIsAnimating);
+        return true;
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        ss.mIsAnimating = mIsAnimating;
+        return ss;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+        mIsAnimating = ss.mIsAnimating;
+    }
+
+    @VisibleForTesting
+    boolean isAnimating() {
+        return mIllustrationView.isAnimating();
+    }
+
+    private void init(Context context, AttributeSet attrs) {
+        setLayoutResource(R.layout.illustration_preference);
+
+        mIsAnimating = true;
+        if (attrs != null) {
+            final TypedArray a = context.obtainStyledAttributes(attrs,
+                    R.styleable.LottieAnimationView, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
+            mAnimationId = a.getResourceId(R.styleable.LottieAnimationView_lottie_rawRes, 0);
+            a.recycle();
+        }
+    }
+
+    private void updateAnimationStatus(boolean playAnimation) {
+        if (playAnimation) {
+            mIllustrationView.resumeAnimation();
+            mPlayButton.setVisibility(View.INVISIBLE);
+        } else {
+            mIllustrationView.pauseAnimation();
+            mPlayButton.setVisibility(View.VISIBLE);
+        }
+    }
+
+    static class SavedState extends BaseSavedState {
+        boolean mIsAnimating;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        /**
+         * Constructor called from {@link #CREATOR}
+         */
+        private SavedState(Parcel in) {
+            super(in);
+            mIsAnimating = (Boolean) in.readValue(null);
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeValue(mIsAnimating);
+        }
+
+        @Override
+        public String toString() {
+            return "IllustrationPreference.SavedState{"
+                    + Integer.toHexString(System.identityHashCode(this))
+                    + " mIsAnimating=" + mIsAnimating + "}";
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+                    public SavedState createFromParcel(Parcel in) {
+                        return new SavedState(in);
+                    }
+
+                    public SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
+    }
+}
diff --git a/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml b/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml
index 0ecf979..017d1fc 100644
--- a/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml
+++ b/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml
@@ -7,7 +7,7 @@
         errorLine1="        android:id=&quot;@android:id/switch_widget&quot;"
         errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="frameworks/base/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml"
+            file="frameworks/base/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml"
             line="49"
             column="9"/>
     </issue>
@@ -15,7 +15,7 @@
     <issue
         id="NewApi"
         message="`@android:style/Widget.Material.CompoundButton.Switch` requires API level 24 (current min is 21)"
-        errorLine1="    &lt;style name=&quot;Settings.MainSwitch&quot; parent=&quot;@android:style/Widget.Material.CompoundButton.Switch&quot;>"
+        errorLine1="    &lt;style name=&quot;MainSwitch.Settingslib&quot; parent=&quot;@android:style/Widget.Material.CompoundButton.Switch&quot;>"
         errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="frameworks/base/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml"
@@ -26,7 +26,7 @@
     <issue
         id="NewApi"
         message="`@android:style/Widget.Material.CompoundButton.Switch` requires API level 24 (current min is 21)"
-        errorLine1="    &lt;style name=&quot;Widget.SwitchBar.Switch&quot; parent=&quot;@android:style/Widget.Material.CompoundButton.Switch&quot;>"
+        errorLine1="    &lt;style name=&quot;SwitchBar.Switch.Settingslib&quot; parent=&quot;@android:style/Widget.Material.CompoundButton.Switch&quot;>"
         errorLine2="                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="frameworks/base/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml"
@@ -37,7 +37,7 @@
     <issue
         id="NewApi"
         message="`android:trackTint` requires API level 23 (current min is 21)"
-        errorLine1="        &lt;item name=&quot;android:trackTint&quot;>@color/switchbar_switch_track_tint&lt;/item>"
+        errorLine1="        &lt;item name=&quot;android:trackTint&quot;>@color/settingslib_switchbar_switch_track_tint&lt;/item>"
         errorLine2="              ~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="frameworks/base/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml"
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml
similarity index 85%
copy from packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
copy to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml
index b646f0a..088e82b 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml
@@ -19,8 +19,8 @@
     android:color="?android:attr/colorControlHighlight">
     <item>
         <shape android:shape="rectangle">
-            <solid android:color="@color/state_off_color"/>
-            <corners android:radius="@dimen/switch_bar_radius"/>
+            <solid android:color="@color/settingslib_state_off_color"/>
+            <corners android:radius="@dimen/settingslib_switch_bar_radius"/>
         </shape>
     </item>
 </ripple>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_off.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml
similarity index 85%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_off.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml
index b646f0a..088e82b 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_off.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml
@@ -19,8 +19,8 @@
     android:color="?android:attr/colorControlHighlight">
     <item>
         <shape android:shape="rectangle">
-            <solid android:color="@color/state_off_color"/>
-            <corners android:radius="@dimen/switch_bar_radius"/>
+            <solid android:color="@color/settingslib_state_off_color"/>
+            <corners android:radius="@dimen/settingslib_switch_bar_radius"/>
         </shape>
     </item>
 </ripple>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml
similarity index 85%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml
index b646f0a..250188b 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_disabled.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml
@@ -19,8 +19,8 @@
     android:color="?android:attr/colorControlHighlight">
     <item>
         <shape android:shape="rectangle">
-            <solid android:color="@color/state_off_color"/>
-            <corners android:radius="@dimen/switch_bar_radius"/>
+            <solid android:color="@color/settingslib_state_on_color"/>
+            <corners android:radius="@dimen/settingslib_switch_bar_radius"/>
         </shape>
     </item>
 </ripple>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_disabled.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml
similarity index 66%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_disabled.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml
index 9e6cfbd..900400e 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_disabled.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_disabled.xml
@@ -17,16 +17,16 @@
 
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:top="@dimen/switch_thumb_margin"
-        android:left="@dimen/switch_thumb_margin"
-        android:right="@dimen/switch_thumb_margin"
-        android:bottom="@dimen/switch_thumb_margin">
+        android:top="@dimen/settingslib_switch_thumb_margin"
+        android:left="@dimen/settingslib_switch_thumb_margin"
+        android:right="@dimen/settingslib_switch_thumb_margin"
+        android:bottom="@dimen/settingslib_switch_thumb_margin">
         <shape android:shape="oval">
             <size
-                android:height="@dimen/switch_thumb_size"
-                android:width="@dimen/switch_thumb_size"/>
+                android:height="@dimen/settingslib_switch_thumb_size"
+                android:width="@dimen/settingslib_switch_thumb_size"/>
             <solid
-                android:color="@color/state_off_color"
+                android:color="@color/settingslib_state_off_color"
                 android:alpha="?android:attr/disabledAlpha"/>
         </shape>
     </item>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_off.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml
similarity index 64%
copy from packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_off.xml
copy to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml
index f6d8815..e54c332 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_off.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_off.xml
@@ -17,15 +17,15 @@
 
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:top="@dimen/switch_thumb_margin"
-        android:left="@dimen/switch_thumb_margin"
-        android:right="@dimen/switch_thumb_margin"
-        android:bottom="@dimen/switch_thumb_margin">
+        android:top="@dimen/settingslib_switch_thumb_margin"
+        android:left="@dimen/settingslib_switch_thumb_margin"
+        android:right="@dimen/settingslib_switch_thumb_margin"
+        android:bottom="@dimen/settingslib_switch_thumb_margin">
         <shape android:shape="oval">
             <size
-                android:height="@dimen/switch_thumb_size"
-                android:width="@dimen/switch_thumb_size"/>
-            <solid android:color="@color/state_off_color"/>
+                android:height="@dimen/settingslib_switch_thumb_size"
+                android:width="@dimen/settingslib_switch_thumb_size"/>
+            <solid android:color="@color/settingslib_state_off_color"/>
         </shape>
     </item>
 </layer-list>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_off.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_on.xml
similarity index 64%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_off.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_on.xml
index f6d8815..0f27fc2 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_off.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_on.xml
@@ -17,15 +17,15 @@
 
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:top="@dimen/switch_thumb_margin"
-        android:left="@dimen/switch_thumb_margin"
-        android:right="@dimen/switch_thumb_margin"
-        android:bottom="@dimen/switch_thumb_margin">
+        android:top="@dimen/settingslib_switch_thumb_margin"
+        android:left="@dimen/settingslib_switch_thumb_margin"
+        android:right="@dimen/settingslib_switch_thumb_margin"
+        android:bottom="@dimen/settingslib_switch_thumb_margin">
         <shape android:shape="oval">
             <size
-                android:height="@dimen/switch_thumb_size"
-                android:width="@dimen/switch_thumb_size"/>
-            <solid android:color="@color/state_off_color"/>
+                android:height="@dimen/settingslib_switch_thumb_size"
+                android:width="@dimen/settingslib_switch_thumb_size"/>
+            <solid android:color="@color/settingslib_state_on_color"/>
         </shape>
     </item>
 </layer-list>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_selector.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_selector.xml
similarity index 72%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_selector.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_selector.xml
index a541eaa..06bb779 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_selector.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_thumb_selector.xml
@@ -16,7 +16,7 @@
   -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/thumb_on" android:state_checked="true"/>
-    <item android:drawable="@drawable/thumb_off" android:state_checked="false"/>
-    <item android:drawable="@drawable/thumb_disabled" android:state_enabled="false"/>
+    <item android:drawable="@drawable/settingslib_thumb_on" android:state_checked="true"/>
+    <item android:drawable="@drawable/settingslib_thumb_off" android:state_checked="false"/>
+    <item android:drawable="@drawable/settingslib_thumb_disabled" android:state_enabled="false"/>
 </selector>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_disabled_background.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_disabled_background.xml
similarity index 76%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/track_disabled_background.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_disabled_background.xml
index b6c7313..15dfcb7 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_disabled_background.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_disabled_background.xml
@@ -17,10 +17,10 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle"
-    android:width="@dimen/switch_track_width"
-    android:height="@dimen/switch_track_height">
+    android:width="@dimen/settingslib_switch_track_width"
+    android:height="@dimen/settingslib_switch_track_height">
     <solid
-        android:color="@color/track_off_color"
+        android:color="@color/settingslib_track_off_color"
         android:alpha="?android:attr/disabledAlpha"/>
-    <corners android:radius="@dimen/switch_track_radius"/>
+    <corners android:radius="@dimen/settingslib_switch_track_radius"/>
 </shape>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_off_background.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_off_background.xml
similarity index 74%
copy from packages/SettingsLib/MainSwitchPreference/res/drawable/track_off_background.xml
copy to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_off_background.xml
index f2c11b6..4d79a6e 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_off_background.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_off_background.xml
@@ -17,8 +17,8 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle"
-    android:width="@dimen/switch_track_width"
-    android:height="@dimen/switch_track_height">
-    <solid android:color="@color/track_off_color"/>
-    <corners android:radius="@dimen/switch_track_radius"/>
+    android:width="@dimen/settingslib_switch_track_width"
+    android:height="@dimen/settingslib_switch_track_height">
+    <solid android:color="@color/settingslib_track_off_color"/>
+    <corners android:radius="@dimen/settingslib_switch_track_radius"/>
 </shape>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_off_background.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_on_background.xml
similarity index 74%
rename from packages/SettingsLib/MainSwitchPreference/res/drawable/track_off_background.xml
rename to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_on_background.xml
index f2c11b6..c12d012 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_off_background.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_on_background.xml
@@ -17,8 +17,8 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle"
-    android:width="@dimen/switch_track_width"
-    android:height="@dimen/switch_track_height">
-    <solid android:color="@color/track_off_color"/>
-    <corners android:radius="@dimen/switch_track_radius"/>
+    android:width="@dimen/settingslib_switch_track_width"
+    android:height="@dimen/settingslib_switch_track_height">
+    <solid android:color="@color/settingslib_track_on_color"/>
+    <corners android:radius="@dimen/settingslib_switch_track_radius"/>
 </shape>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_selector.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_selector.xml
similarity index 69%
copy from packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_selector.xml
copy to packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_selector.xml
index a541eaa..a38c3b4 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_selector.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_track_selector.xml
@@ -16,7 +16,7 @@
   -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/thumb_on" android:state_checked="true"/>
-    <item android:drawable="@drawable/thumb_off" android:state_checked="false"/>
-    <item android:drawable="@drawable/thumb_disabled" android:state_enabled="false"/>
+    <item android:drawable="@drawable/settingslib_track_on_background" android:state_checked="true"/>
+    <item android:drawable="@drawable/settingslib_track_off_background" android:state_checked="false"/>
+    <item android:drawable="@drawable/settingslib_track_disabled_background" android:state_enabled="false"/>
 </selector>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_on.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_on.xml
deleted file mode 100644
index afea8bd..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/switch_bar_bg_on.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight">
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@color/state_on_color"/>
-            <corners android:radius="@dimen/switch_bar_radius"/>
-        </shape>
-    </item>
-</ripple>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_on.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_on.xml
deleted file mode 100644
index 61230b5..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/thumb_on.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:top="@dimen/switch_thumb_margin"
-        android:left="@dimen/switch_thumb_margin"
-        android:right="@dimen/switch_thumb_margin"
-        android:bottom="@dimen/switch_thumb_margin">
-        <shape android:shape="oval">
-            <size
-                android:height="@dimen/switch_thumb_size"
-                android:width="@dimen/switch_thumb_size"/>
-            <solid android:color="@color/state_on_color"/>
-        </shape>
-    </item>
-</layer-list>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_on_background.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/track_on_background.xml
deleted file mode 100644
index 9246462..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_on_background.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle"
-    android:width="@dimen/switch_track_width"
-    android:height="@dimen/switch_track_height">
-    <solid android:color="@color/track_on_color"/>
-    <corners android:radius="@dimen/switch_track_radius"/>
-</shape>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_selector.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable/track_selector.xml
deleted file mode 100644
index 50a03b9..0000000
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/track_selector.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2020 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/track_on_background" android:state_checked="true"/>
-    <item android:drawable="@drawable/track_off_background" android:state_checked="false"/>
-    <item android:drawable="@drawable/track_disabled_background" android:state_enabled="false"/>
-</selector>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
similarity index 76%
rename from packages/SettingsLib/MainSwitchPreference/res/layout-v31/main_switch_bar.xml
rename to packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index 9ccf63a..27c30ca6 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -28,11 +28,11 @@
 
     <LinearLayout
         android:id="@+id/frame"
-        android:minHeight="@dimen/min_switch_bar_height"
+        android:minHeight="@dimen/settingslib_min_switch_bar_height"
         android:layout_height="wrap_content"
         android:layout_width="match_parent"
-        android:paddingLeft="@dimen/switchbar_margin_start"
-        android:paddingRight="@dimen/switchbar_margin_end">
+        android:paddingLeft="@dimen/settingslib_switchbar_margin_start"
+        android:paddingRight="@dimen/settingslib_switchbar_margin_end">
 
         <TextView
             android:id="@+id/switch_text"
@@ -44,16 +44,16 @@
             android:maxLines="2"
             android:ellipsize="end"
             android:textAppearance="?android:attr/textAppearanceListItem"
-            style="@style/MainSwitchText" />
+            style="@style/MainSwitchText.Settingslib" />
 
         <ImageView
             android:id="@+id/restricted_icon"
-            android:layout_width="@dimen/restricted_icon_size"
-            android:layout_height="@dimen/restricted_icon_size"
+            android:layout_width="@dimen/settingslib_restricted_icon_size"
+            android:layout_height="@dimen/settingslib_restricted_icon_size"
             android:tint="?android:attr/colorAccent"
             android:theme="@android:style/Theme.Material"
             android:layout_gravity="center_vertical"
-            android:layout_marginEnd="@dimen/restricted_icon_margin_end"
+            android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
             android:src="@*android:drawable/ic_info"
             android:visibility="gone" />
 
@@ -62,9 +62,9 @@
             android:layout_width="wrap_content"
             android:layout_height="48dp"
             android:layout_gravity="center_vertical"
-            android:track="@drawable/track_selector"
-            android:thumb="@drawable/thumb_selector"
-            android:theme="@style/Settings.MainSwitch"/>
+            android:track="@drawable/settingslib_track_selector"
+            android:thumb="@drawable/settingslib_thumb_selector"
+            android:theme="@style/MainSwitch.Settingslib"/>
     </LinearLayout>
 
 </LinearLayout>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
similarity index 79%
rename from packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml
rename to packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
index ac82733..306145a 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
@@ -31,17 +31,17 @@
         android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
         android:textSize="16sp"
         android:textColor="?android:attr/textColorPrimaryInverse"
-        android:layout_marginStart="@dimen/switchbar_subsettings_margin_start"
+        android:layout_marginStart="@dimen/settingslib_switchbar_subsettings_margin_start"
         android:textAlignment="viewStart"/>
 
     <ImageView
         android:id="@+id/restricted_icon"
-        android:layout_width="@dimen/restricted_icon_size"
-        android:layout_height="@dimen/restricted_icon_size"
+        android:layout_width="@dimen/settingslib_restricted_icon_size"
+        android:layout_height="@dimen/settingslib_restricted_icon_size"
         android:tint="?android:attr/colorAccent"
         android:theme="@android:style/Theme.Material"
         android:layout_gravity="center_vertical"
-        android:layout_marginEnd="@dimen/restricted_icon_margin_end"
+        android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
         android:src="@*android:drawable/ic_info"
         android:visibility="gone"/>
 
@@ -50,7 +50,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
-        android:layout_marginEnd="@dimen/switchbar_subsettings_margin_end"
-        android:theme="@style/Widget.SwitchBar.Switch"/>
+        android:layout_marginEnd="@dimen/settingslib_switchbar_subsettings_margin_end"
+        android:theme="@style/SwitchBar.Switch.Settingslib"/>
 </LinearLayout>
 
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_layout.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml
similarity index 94%
rename from packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_layout.xml
rename to packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml
index efc047c..eccf0c0 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/main_switch_layout.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml
@@ -20,7 +20,7 @@
     android:layout_width="match_parent" >
 
     <com.android.settingslib.widget.MainSwitchBar
-        android:id="@+id/main_switch_bar"
+        android:id="@+id/settingslib_main_switch_bar"
         android:visibility="gone"
         android:layout_height="wrap_content"
         android:layout_width="match_parent" />
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml b/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
index 7457285..c8d06d4 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
@@ -16,9 +16,9 @@
   -->
 
 <resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <color name="switchbar_switch_track_tint">#82000000</color>
-    <color name="switchbar_switch_thumb_tint">@android:color/black</color>
+    <color name="settingslib_switchbar_switch_track_tint">#82000000</color>
+    <color name="settingslib_switchbar_switch_thumb_tint">@android:color/black</color>
 
     <!-- Material next track on color-->
-    <color name="track_on_color">?androidprv:attr/colorSurfaceHighlight</color>
+    <color name="settingslib_track_on_color">?androidprv:attr/colorSurfaceHighlight</color>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-sw600dp/dmiens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-sw600dp/dmiens.xml
index c6bb77d..55a2589 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values-sw600dp/dmiens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-sw600dp/dmiens.xml
@@ -18,5 +18,5 @@
 <resources>
 
     <!-- SwitchBar sub settings margin start / end -->
-    <dimen name="switchbar_subsettings_margin_start">80dp</dimen>
+    <dimen name="settingslib_switchbar_subsettings_margin_start">80dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp-land/dmiens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp-land/dmiens.xml
index 3e941c2..53995bc 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp-land/dmiens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp-land/dmiens.xml
@@ -18,6 +18,6 @@
 <resources>
 
     <!-- SwitchBar sub settings margin start / end -->
-    <dimen name="switchbar_subsettings_margin_start">128dp</dimen>
-    <dimen name="switchbar_subsettings_margin_end">128dp</dimen>
+    <dimen name="settingslib_switchbar_subsettings_margin_start">128dp</dimen>
+    <dimen name="settingslib_switchbar_subsettings_margin_end">128dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp/dmiens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp/dmiens.xml
index 2f040da..9015c58 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp/dmiens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-sw720dp/dmiens.xml
@@ -18,6 +18,6 @@
 <resources>
 
     <!-- SwitchBar sub settings margin start / end -->
-    <dimen name="switchbar_subsettings_margin_start">80dp</dimen>
-    <dimen name="switchbar_subsettings_margin_end">80dp</dimen>
+    <dimen name="settingslib_switchbar_subsettings_margin_start">80dp</dimen>
+    <dimen name="settingslib_switchbar_subsettings_margin_end">80dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml b/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
index ea7bfd4..3fcc1dd 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
@@ -16,19 +16,19 @@
   -->
 
 <resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <color name="switchbar_background_color">@*android:color/material_grey_600</color>
-    <color name="switchbar_switch_track_tint">#BFFFFFFF</color>
-    <color name="switchbar_switch_thumb_tint">@android:color/white</color>
+    <color name="settingslib_switchbar_background_color">@*android:color/material_grey_600</color>
+    <color name="settingslib_switchbar_switch_track_tint">#BFFFFFFF</color>
+    <color name="settingslib_switchbar_switch_thumb_tint">@android:color/white</color>
 
     <!-- Material next state on color-->
-    <color name="state_on_color">?androidprv:attr/colorAccentPrimary</color>
+    <color name="settingslib_state_on_color">?androidprv:attr/colorAccentPrimary</color>
 
     <!-- Material next state off color-->
-    <color name="state_off_color">?androidprv:attr/colorAccentSecondary</color>
+    <color name="settingslib_state_off_color">?androidprv:attr/colorAccentSecondary</color>
 
     <!-- Material next track on color-->
-    <color name="track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
+    <color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
 
     <!-- Material next track off color-->
-    <color name="track_off_color">?androidprv:attr/colorAccentSecondaryVariant</color>
+    <color name="settingslib_track_off_color">?androidprv:attr/colorAccentSecondaryVariant</color>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
index 67886bc..4c528da 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
@@ -18,42 +18,42 @@
 <resources>
 
     <!-- Size of layout margin left -->
-    <dimen name="switchbar_margin_start">24dp</dimen>
+    <dimen name="settingslib_switchbar_margin_start">24dp</dimen>
 
     <!-- Size of layout margin right -->
-    <dimen name="switchbar_margin_end">16dp</dimen>
+    <dimen name="settingslib_switchbar_margin_end">16dp</dimen>
 
     <!-- Minimum width of switch -->
-    <dimen name="min_switch_width">52dp</dimen>
+    <dimen name="settingslib_min_switch_width">52dp</dimen>
 
     <!-- Minimum width of switch bar -->
-    <dimen name="min_switch_bar_height">72dp</dimen>
+    <dimen name="settingslib_min_switch_bar_height">72dp</dimen>
 
     <!-- Restricted icon size in switch bar -->
-    <dimen name="restricted_icon_size">@*android:dimen/config_restrictedIconSize</dimen>
+    <dimen name="settingslib_restricted_icon_size">@*android:dimen/config_restrictedIconSize</dimen>
 
     <!-- Restricted icon in switch bar -->
-    <dimen name="restricted_icon_margin_end">16dp</dimen>
+    <dimen name="settingslib_restricted_icon_margin_end">16dp</dimen>
 
     <!-- Radius of switch bar -->
-    <dimen name="switch_bar_radius">28dp</dimen>
+    <dimen name="settingslib_switch_bar_radius">28dp</dimen>
 
     <!-- Margin of switch thumb -->
-    <dimen name="switch_thumb_margin">4dp</dimen>
+    <dimen name="settingslib_switch_thumb_margin">4dp</dimen>
 
     <!-- Size of switch thumb -->
-    <dimen name="switch_thumb_size">20dp</dimen>
+    <dimen name="settingslib_switch_thumb_size">20dp</dimen>
 
     <!-- Width of switch track -->
-    <dimen name="switch_track_width">52dp</dimen>
+    <dimen name="settingslib_switch_track_width">52dp</dimen>
 
     <!-- Height of switch track -->
-    <dimen name="switch_track_height">28dp</dimen>
+    <dimen name="settingslib_switch_track_height">28dp</dimen>
 
     <!-- Radius of switch track -->
-    <dimen name="switch_track_radius">35dp</dimen>
+    <dimen name="settingslib_switch_track_radius">35dp</dimen>
 
     <!-- SwitchBar sub settings margin start / end -->
-    <dimen name="switchbar_subsettings_margin_start">72dp</dimen>
-    <dimen name="switchbar_subsettings_margin_end">16dp</dimen>
+    <dimen name="settingslib_switchbar_subsettings_margin_start">72dp</dimen>
+    <dimen name="settingslib_switchbar_subsettings_margin_end">16dp</dimen>
 </resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
index 5867695..472025a 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
@@ -17,19 +17,19 @@
 
 <resources>
 
-    <style name="MainSwitchText">
+    <style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
         <item name="android:textSize">20sp</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
         <item name="android:textColor">@android:color/black</item>
     </style>
 
-    <style name="Settings.MainSwitch" parent="@android:style/Widget.Material.CompoundButton.Switch">
-        <item name="android:switchMinWidth">@dimen/min_switch_width</item>
+    <style name="MainSwitch.Settingslib" parent="@android:style/Widget.Material.CompoundButton.Switch">
+        <item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
     </style>
 
-    <style name="Widget.SwitchBar.Switch" parent="@android:style/Widget.Material.CompoundButton.Switch">
-        <item name="android:trackTint">@color/switchbar_switch_track_tint</item>
-        <item name="android:thumbTint">@color/switchbar_switch_thumb_tint</item>
+    <style name="SwitchBar.Switch.Settingslib" parent="@android:style/Widget.Material.CompoundButton.Switch">
+        <item name="android:trackTint">@color/settingslib_switchbar_switch_track_tint</item>
+        <item name="android:thumbTint">@color/settingslib_switchbar_switch_thumb_tint</item>
         <item name="android:minHeight">48dp</item>
         <item name="android:minWidth">48dp</item>
     </style>
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 7913e0a..123c477 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -72,14 +72,13 @@
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
-        LayoutInflater.from(context).inflate(resourceId(context, "layout", "main_switch_bar"),
-                this);
+        LayoutInflater.from(context).inflate(R.layout.settingslib_main_switch_bar, this);
 
         if (!BuildCompat.isAtLeastS()) {
             final TypedArray a = context.obtainStyledAttributes(
                     new int[]{android.R.attr.colorAccent});
             mBackgroundActivatedColor = a.getColor(0, 0);
-            mBackgroundColor = context.getColor(R.color.switchbar_background_color);
+            mBackgroundColor = context.getColor(R.color.settingslib_switchbar_background_color);
             a.recycle();
         }
 
@@ -89,9 +88,10 @@
         mFrameView = findViewById(R.id.frame);
         mTextView = (TextView) findViewById(R.id.switch_text);
         mSwitch = (Switch) findViewById(android.R.id.switch_widget);
-        mBackgroundOn = getContext().getDrawable(R.drawable.switch_bar_bg_on);
-        mBackgroundOff = getContext().getDrawable(R.drawable.switch_bar_bg_off);
-        mBackgroundDisabled = getContext().getDrawable(R.drawable.switch_bar_bg_disabled);
+        mBackgroundOn = getContext().getDrawable(R.drawable.settingslib_switch_bar_bg_on);
+        mBackgroundOff = getContext().getDrawable(R.drawable.settingslib_switch_bar_bg_off);
+        mBackgroundDisabled = getContext().getDrawable(
+                R.drawable.settingslib_switch_bar_bg_disabled);
 
         addOnSwitchChangeListener((switchView, isChecked) -> setChecked(isChecked));
 
@@ -298,8 +298,4 @@
 
         requestLayout();
     }
-
-    private int resourceId(Context context, String type, String name) {
-        return context.getResources().getIdentifier(name, type, context.getPackageName());
-    }
 }
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
index cafc703..6f371ce 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
@@ -66,13 +66,13 @@
         holder.setDividerAllowedAbove(false);
         holder.setDividerAllowedBelow(false);
 
-        mMainSwitchBar = (MainSwitchBar) holder.findViewById(R.id.main_switch_bar);
+        mMainSwitchBar = (MainSwitchBar) holder.findViewById(R.id.settingslib_main_switch_bar);
         updateStatus(isChecked());
         registerListenerToSwitchBar();
     }
 
     private void init(Context context, AttributeSet attrs) {
-        setLayoutResource(R.layout.main_switch_layout);
+        setLayoutResource(R.layout.settingslib_main_switch_layout);
 
         if (attrs != null) {
             final TypedArray a = context.obtainStyledAttributes(attrs,
diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java
index 154a0f4..304c343 100644
--- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java
@@ -36,6 +36,7 @@
     private SettingsSpinnerAdapter mAdapter;
     private AdapterView.OnItemSelectedListener mListener;
     private int mPosition; //Default 0 for internal shard storage.
+    private boolean mIsClickable = true;
 
     /**
      * Perform inflation from XML and apply a class-specific base style.
@@ -50,6 +51,7 @@
     public SettingsSpinnerPreference(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         setLayoutResource(R.layout.settings_spinner_preference);
+        setSelectable(false);
     }
 
     /**
@@ -62,6 +64,7 @@
     public SettingsSpinnerPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         setLayoutResource(R.layout.settings_spinner_preference);
+        setSelectable(false);
     }
 
     /**
@@ -98,10 +101,21 @@
         notifyChanged();
     }
 
+    /** Set clickable of the spinner. */
+    public void setClickable(boolean isClickable) {
+        if (mIsClickable == isClickable) {
+            return;
+        }
+        mIsClickable = isClickable;
+        notifyChanged();
+    }
+
     @Override
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
         final SettingsSpinner spinner = (SettingsSpinner) holder.findViewById(R.id.spinner);
+        spinner.setEnabled(mIsClickable);
+        spinner.setClickable(mIsClickable);
         spinner.setAdapter(mAdapter);
         spinner.setSelection(mPosition);
         spinner.setOnItemSelectedListener(mOnSelectedListener);
diff --git a/packages/SettingsLib/TwoTargetPreference/src/com/android/settingslib/widget/TwoTargetPreference.java b/packages/SettingsLib/TwoTargetPreference/src/com/android/settingslib/widget/TwoTargetPreference.java
index 17f257d..9130662 100644
--- a/packages/SettingsLib/TwoTargetPreference/src/com/android/settingslib/widget/TwoTargetPreference.java
+++ b/packages/SettingsLib/TwoTargetPreference/src/com/android/settingslib/widget/TwoTargetPreference.java
@@ -72,9 +72,9 @@
     private void init(Context context) {
         setLayoutResource(R.layout.preference_two_target);
         mSmallIconSize = context.getResources().getDimensionPixelSize(
-                resourceId(context, "dimen", "two_target_pref_small_icon_size"));
+                R.dimen.two_target_pref_small_icon_size);
         mMediumIconSize = context.getResources().getDimensionPixelSize(
-                resourceId(context, "dimen", "two_target_pref_medium_icon_size"));
+                R.dimen.two_target_pref_medium_icon_size);
         final int secondTargetResId = getSecondTargetResId();
         if (secondTargetResId != 0) {
             setWidgetLayoutResource(secondTargetResId);
@@ -116,8 +116,4 @@
     protected int getSecondTargetResId() {
         return 0;
     }
-
-    private int resourceId(Context context, String type, String name) {
-        return context.getResources().getIdentifier(name, type, context.getPackageName());
-    }
 }
diff --git a/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml b/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
index 8c20e02..ea033a3 100644
--- a/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
+++ b/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
@@ -22,8 +22,8 @@
     android:layout_height="wrap_content"
     android:gravity="center_vertical"
     android:orientation="vertical"
-    android:layout_marginStart="16dp"
-    android:layout_marginEnd="16dp"
+    android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
+    android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
     android:paddingBottom="16dp">
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -70,6 +70,7 @@
         android:id="@+id/bottom_summary"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
         android:visibility="gone"
         android:ellipsize="marquee"
         android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
diff --git a/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_0.xml b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_0.xml
new file mode 100644
index 0000000..efae569
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_0.xml
@@ -0,0 +1,30 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M20.66,7C18.19,5.07 15.14,4 12,4C8.58,4 5.27,5.27 2.7,7.53L12,18.85l6,-7.3v3.15L12,22L0,7.39C2.97,4.08 7.25,2 12,2c4.56,0 8.69,1.92 11.64,5H20.66z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,10h-2v8h2V10z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,20h-2v2h2V20z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_1.xml b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_1.xml
new file mode 100644
index 0000000..d50e734
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_1.xml
@@ -0,0 +1,30 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M23.62,7C20.65,3.93 16.6,2 12,2C7.2,2 3,4.1 0,7.4L12,22l6,-7.3v-3.19l-2.13,2.59C14.74,13.4 13.39,13 12,13s-2.74,0.4 -3.87,1.1L2.7,7.5C5.3,5.3 8.6,4 12,4c3.13,0 6.18,1.1 8.68,3H23.62z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,10h-2v8h2V10z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,20h-2v2h2V20z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_2.xml b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_2.xml
new file mode 100644
index 0000000..1be297e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_2.xml
@@ -0,0 +1,30 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M23.62,7C20.65,3.93 16.6,2 12,2C7.2,2 3,4.1 0,7.4L12,22l6,-7.3v-3.19l-0.27,0.33C16.12,10.67 14.09,10 12,10c-2.09,0 -4.12,0.67 -5.73,1.84L2.7,7.5C5.3,5.3 8.6,4 12,4c3.13,0 6.18,1.1 8.68,3H23.62z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,10h-2v8h2V10z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,20h-2v2h2V20z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_3.xml b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_3.xml
new file mode 100644
index 0000000..738bd5a
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_3.xml
@@ -0,0 +1,30 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M0,7.4L12,22l6,-7.3V8.57C16.21,7.56 14.14,7 12,7C9.2,7 6.53,7.96 4.45,9.62L2.7,7.5C5.3,5.3 8.6,4 12,4c3.13,0 6.18,1.1 8.68,3h2.95C20.65,3.93 16.6,2 12,2C7.2,2 3,4.1 0,7.4z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,10h-2v8h2V10z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,20h-2v2h2V20z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_4.xml b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_4.xml
new file mode 100644
index 0000000..14d020b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_no_internet_wifi_signal_4.xml
@@ -0,0 +1,30 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M0,7.4C3,4.1 7.2,2 12,2c4.6,0 8.65,1.93 11.62,5H18v7.7L12,22L0,7.4z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,10h-2v8h2V10z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,20h-2v2h2V20z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index b96a4f5..e8da28f 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -118,7 +118,7 @@
     <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Цуцлах"</string>
     <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Хослуулснаар холбогдсон үед таны харилцагчид болон дуудлагын түүхэд хандах боломжтой."</string>
     <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай хослуулж чадсангүй."</string>
-    <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Буруу PIN эсхүл дамжих түлхүүрээс шалтгаалан <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай хослуулж чадсангүй."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Буруу ПИН эсхүл дамжих түлхүүрээс шалтгаалан <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай хослуулж чадсангүй."</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай холбоо барих боломжгүй."</string>
     <string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"Хослуулахаас <xliff:g id="DEVICE_NAME">%1$s</xliff:g> татгалзсан."</string>
     <string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Компьютер"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index ca185e2..645248c 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -504,7 +504,7 @@
     <string name="cancel" msgid="5665114069455378395">"रद्द गर्नुहोस्"</string>
     <string name="okay" msgid="949938843324579502">"ठिक छ"</string>
     <string name="alarms_and_reminders_label" msgid="6918395649731424294">"अलार्म र रिमाइन्डरहरू"</string>
-    <string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"अलार्म तथा रिमाइन्डर सेट गर्न दिनुहोस्"</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" product="default" msgid="1122213569699233612">"यो एपलाई अलार्म सेट गर्न तथा अन्य कार्यको समयतालिका तोक्न दिनुहोस्। तपाईंले आफ्नो फोन नचलाएका बेला पनि यो एप प्रयोग गरिन सक्छ। यसले गर्दा थप ब्याट्री खपत हुन सक्छ। यो अनुमति नदिइएका खण्डमा यो एप राम्ररी नचल्न सक्छ र यो एपका अलार्म पनि तोकिएको समयमा बज्ने छैनन्।"</string>
     <string name="alarms_and_reminders_footer_title" product="tablet" msgid="4596201244991057839">"यो एपलाई अलार्म सेट गर्न तथा अन्य कार्यको समयतालिका तोक्न दिनुहोस्। तपाईंले आफ्नो ट्याब्लेट नचलाएका बेला पनि यो एप प्रयोग गरिन सक्छ। यसले गर्दा थप ब्याट्री खपत हुन सक्छ। यो अनुमति नदिइएका खण्डमा यो एप राम्ररी नचल्न सक्छ र यो एपका अलार्म पनि तोकिएको समयमा बज्ने छैनन्।"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 70b826a..404299a 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1147,8 +1147,8 @@
     <string name="battery_info_status_charging_wireless">Charging wirelessly</string>
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_discharging">Not charging</string>
-    <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
-    <string name="battery_info_status_not_charging">Plugged in, can\'t charge right now</string>
+    <!-- Battery Info screen. Value for a status item. A state which device is connected with any charger(e.g. USB, Adapter or Wireless) but not charging yet. Used for diagnostic info screens, precise translation isn't needed -->
+    <string name="battery_info_status_not_charging">Connected, not charging</string>
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_full">Charged</string>
 
@@ -1422,7 +1422,7 @@
     <string name="user_set_lock_button">Set lock</string>
     <!-- Label for switching to other user in the user switcher [CHAR LIMIT=35] -->
     <string name="user_switch_to_user">Switch to <xliff:g id="user_name" example="John Doe">%s</xliff:g></string>
-    <!-- Dialog message when creating a new user [CHAR LIMIT=40] -->
+    <!-- Dialog message when creating a new user [CHAR LIMIT=NONE] -->
     <string name="creating_new_user_dialog_message">Creating new user…</string>
     <!-- Text shown to notify that the creation of new user has failed. [CHAR LIMIT=40] -->
     <string name="add_user_failed">Failed to create a new user</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
index 9889419..4dd3ff1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java
@@ -187,8 +187,9 @@
     }
 
     protected int getIconColorAttr() {
-        return (mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED)
-                ? android.R.attr.colorAccent : android.R.attr.colorControlNormal;
+        final boolean accent = (mWifiEntry.hasInternetAccess()
+                && mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED);
+        return accent ? android.R.attr.colorAccent : android.R.attr.colorControlNormal;
     }
 
     private void updateIcon(boolean showX, int level) {
@@ -267,7 +268,7 @@
         }
 
         public Drawable getIcon(boolean showX, int level) {
-            return mContext.getDrawable(Utils.getWifiIconResource(showX, level));
+            return mContext.getDrawable(WifiUtils.getInternetIconResource(level, showX));
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index 15b146d..6100615 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -36,6 +36,22 @@
 
     private static final int INVALID_RSSI = -127;
 
+    static final int[] WIFI_PIE = {
+            com.android.internal.R.drawable.ic_wifi_signal_0,
+            com.android.internal.R.drawable.ic_wifi_signal_1,
+            com.android.internal.R.drawable.ic_wifi_signal_2,
+            com.android.internal.R.drawable.ic_wifi_signal_3,
+            com.android.internal.R.drawable.ic_wifi_signal_4
+    };
+
+    static final int[] NO_INTERNET_WIFI_PIE = {
+            R.drawable.ic_no_internet_wifi_signal_0,
+            R.drawable.ic_no_internet_wifi_signal_1,
+            R.drawable.ic_no_internet_wifi_signal_2,
+            R.drawable.ic_no_internet_wifi_signal_3,
+            R.drawable.ic_no_internet_wifi_signal_4
+    };
+
     public static String buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config) {
         final StringBuilder summary = new StringBuilder();
         final WifiInfo info = accessPoint.getInfo();
@@ -245,6 +261,20 @@
         return context.getString(R.string.wifi_unmetered_label);
     }
 
+    /**
+     * Returns the Internet icon resource for a given RSSI level.
+     *
+     * @param level The number of bars to show (0-4)
+     * @param noInternet True if a connected Wi-Fi network cannot access the Internet
+     * @throws IllegalArgumentException if an invalid RSSI level is given.
+     */
+    public static int getInternetIconResource(int level, boolean noInternet) {
+        if (level < 0 || level >= WIFI_PIE.length) {
+            throw new IllegalArgumentException("No Wifi icon found for level: " + level);
+        }
+        return noInternet ? NO_INTERNET_WIFI_PIE[level] : WIFI_PIE[level];
+    }
+
     public static boolean isMeteredOverridden(WifiConfiguration config) {
         return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE;
     }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java
index 53a382a..b0c5314 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java
@@ -89,4 +89,24 @@
         assertThat(mSpinnerPreference.getSelectedItem())
                 .isEqualTo(mSpinner.getAdapter().getItem(1));
     }
+
+    @Test
+    public void onBindViewHolder_setClickableTrue_isClickableTrue() {
+        mSpinnerPreference.setClickable(true);
+
+        mSpinnerPreference.onBindViewHolder(mViewHolder);
+
+        assertThat(mSpinner.isClickable()).isTrue();
+        assertThat(mSpinner.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void onBindViewHolder_setClickableFalse_isClickableFalse() {
+        mSpinnerPreference.setClickable(false);
+
+        mSpinnerPreference.onBindViewHolder(mViewHolder);
+
+        assertThat(mSpinner.isClickable()).isFalse();
+        assertThat(mSpinner.isEnabled()).isFalse();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
new file mode 100644
index 0000000..4a14403
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.settingslib.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.airbnb.lottie.LottieAnimationView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+public class IllustrationPreferenceTest {
+
+    @Mock
+    LottieAnimationView mAnimationView;
+
+    private IllustrationPreference mPreference;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        final Context context = RuntimeEnvironment.application;
+        final AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
+        mPreference = new IllustrationPreference(context, attributeSet);
+        ReflectionHelpers.setField(mPreference, "mIllustrationView", mAnimationView);
+    }
+
+    @Test
+    public void isAnimating_lottieAnimationViewIsNotAnimating_shouldReturnFalse() {
+        when(mAnimationView.isAnimating()).thenReturn(false);
+
+        assertThat(mPreference.isAnimating()).isFalse();
+    }
+
+    @Test
+    public void isAnimating_lottieAnimationViewIsAnimating_shouldReturnTrue() {
+        when(mAnimationView.isAnimating()).thenReturn(true);
+
+        assertThat(mPreference.isAnimating()).isTrue();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java
index 12f329d..e58c04a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java
@@ -41,7 +41,8 @@
     @Before
     public void setUp() {
         mContext = RuntimeEnvironment.application;
-        mRootView = View.inflate(mContext, R.layout.main_switch_layout, null /* parent */);
+        mRootView = View.inflate(mContext, R.layout.settingslib_main_switch_layout,
+                null /* parent */);
         mHolder = PreferenceViewHolder.createInstanceForTests(mRootView);
         mPreference = new MainSwitchPreference(mContext);
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 941f47f..3219b2b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -34,8 +34,11 @@
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.backup.BackupManager;
+import android.app.compat.CompatChanges;
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -350,6 +353,9 @@
     public static String keyToString(int key) {
         return SettingsState.keyToString(key);
     }
+    @ChangeId
+    @EnabledSince(targetSdkVersion=android.os.Build.VERSION_CODES.S)
+    private static final long ENFORCE_READ_PERMISSION_FOR_MULTI_SIM_DATA_CALL = 172670679L;
 
     @Override
     public boolean onCreate() {
@@ -1950,6 +1956,25 @@
             // Skip checking readable annotations for test_only apps
             checkReadableAnnotation(settingsType, settingName);
         }
+        /**
+         * some settings need additional permission check, this is to have a matching security
+         * control from other API alternatives returning the same settings values.
+         * note, the permission enforcement should be based on app's targetSDKlevel to better handle
+         * app-compat.
+         */
+        switch (settingName) {
+            // missing READ_PRIVILEGED_PHONE_STATE permission protection
+            // see alternative API {@link SubscriptionManager#getPreferredDataSubscriptionId()
+            case Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION:
+                // app-compat handling, not break apps targeting on previous SDKs.
+                if (CompatChanges.isChangeEnabled(
+                        ENFORCE_READ_PERMISSION_FOR_MULTI_SIM_DATA_CALL)) {
+                    getContext().enforceCallingOrSelfPermission(
+                            Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+                            "access global settings MULTI_SIM_DATA_CALL_SUBSCRIPTION");
+                }
+                break;
+        }
         if (!ai.isInstantApp()) {
             return;
         }
@@ -4919,6 +4944,15 @@
                                     String.valueOf(defAccessibilityButtonMode), /* tag= */
                                     null, /* makeDefault= */ true,
                                     SettingsState.SYSTEM_PACKAGE_NAME);
+
+                            if (hasValueInA11yButtonTargets(secureSettings)) {
+                                secureSettings.insertSettingLocked(
+                                        Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
+                                        /* enabled */ "1",
+                                        /* tag= */ null,
+                                        /* makeDefault= */ false,
+                                        SettingsState.SYSTEM_PACKAGE_NAME);
+                            }
                         }
                     }
 
@@ -5145,13 +5179,21 @@
         }
 
         private boolean isAccessibilityButtonInNavigationBarOn(SettingsState secureSettings) {
-            final boolean hasValueInA11yBtnTargets = !TextUtils.isEmpty(
-                    secureSettings.getSettingLocked(
-                            Secure.ACCESSIBILITY_BUTTON_TARGETS).getValue());
+            return hasValueInA11yButtonTargets(secureSettings) && !isGestureNavigateEnabled();
+        }
+
+        private boolean isGestureNavigateEnabled() {
             final int navigationMode = getContext().getResources().getInteger(
                     com.android.internal.R.integer.config_navBarInteractionMode);
+            return navigationMode == NAV_BAR_MODE_GESTURAL;
+        }
 
-            return hasValueInA11yBtnTargets && (navigationMode != NAV_BAR_MODE_GESTURAL);
+        private boolean hasValueInA11yButtonTargets(SettingsState secureSettings) {
+            final Setting a11yButtonTargetsSettings =
+                    secureSettings.getSettingLocked(Secure.ACCESSIBILITY_BUTTON_TARGETS);
+
+            return !a11yButtonTargetsSettings.isNull()
+                    && !TextUtils.isEmpty(a11yButtonTargetsSettings.getValue());
         }
     }
 }
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 22e38f4..3a82434 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -752,6 +752,7 @@
                  Settings.Secure.SUPPRESS_DOZE,
                  Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED,
                  Settings.Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT,
+                 Settings.Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
                  Settings.Secure.UI_TRANSLATION_ENABLED);
 
     @Test
diff --git a/packages/SystemUI/res/drawable/accessibility_floating_tooltip_background.xml b/packages/SystemUI/res/drawable/accessibility_floating_tooltip_background.xml
new file mode 100644
index 0000000..46e7dcc
--- /dev/null
+++ b/packages/SystemUI/res/drawable/accessibility_floating_tooltip_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+       android:shape="rectangle">
+    <solid android:color="?androidprv:attr/colorAccentPrimary" />
+    <corners android:radius="@dimen/accessibility_floating_tooltip_text_corner_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/wallet_action_button_bg.xml b/packages/SystemUI/res/drawable/wallet_action_button_bg.xml
index bf7625f..925ab67 100644
--- a/packages/SystemUI/res/drawable/wallet_action_button_bg.xml
+++ b/packages/SystemUI/res/drawable/wallet_action_button_bg.xml
@@ -14,13 +14,14 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
 -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <item>
         <shape android:shape="rectangle">
         <stroke
             android:width="1dp"
-            android:color="@color/GM2_blue_600"/>
-        <solid android:color="@color/GM2_blue_600"/>
+            android:color="?androidprv:attr/colorAccentPrimary"/>
+        <solid android:color="?androidprv:attr/colorAccentPrimary"/>
         <corners android:radius="24dp"/>
         </shape>
     </item>
diff --git a/packages/SystemUI/res/drawable/wallet_empty_state_bg.xml b/packages/SystemUI/res/drawable/wallet_empty_state_bg.xml
index f52889a..b203228 100644
--- a/packages/SystemUI/res/drawable/wallet_empty_state_bg.xml
+++ b/packages/SystemUI/res/drawable/wallet_empty_state_bg.xml
@@ -15,7 +15,7 @@
   ~ limitations under the License.
   -->
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight">
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <item android:id="@android:id/mask">
     <shape android:shape="rectangle">
         <solid android:color="#DADCE0" />
@@ -26,7 +26,7 @@
         <shape>
         <stroke
             android:width="1dp"
-            android:color="@color/GM2_grey_900" />
+            android:color="?androidprv:attr/colorAccentPrimary" />
         <corners android:radius="@dimen/wallet_empty_state_corner_radius" />
         </shape>
     </item>
diff --git a/packages/SystemUI/res/layout/accessibility_floating_menu_tooltip.xml b/packages/SystemUI/res/layout/accessibility_floating_menu_tooltip.xml
new file mode 100644
index 0000000..5e7b7e1
--- /dev/null
+++ b/packages/SystemUI/res/layout/accessibility_floating_menu_tooltip.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tooltip"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal">
+
+    <View
+        android:id="@+id/arrow_left"
+        android:layout_width="@dimen/accessibility_floating_tooltip_arrow_width"
+        android:layout_height="@dimen/accessibility_floating_tooltip_arrow_height"
+        android:layout_marginRight="@dimen/accessibility_floating_tooltip_arrow_margin"
+        android:visibility="gone"
+        android:layout_gravity="center_vertical"/>
+
+    <TextView
+        android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:padding="@dimen/accessibility_floating_tooltip_padding"
+        android:background="@drawable/accessibility_floating_tooltip_background"
+        android:textColor="@android:color/black"
+        android:textColorLink="@android:color/black"
+        android:text="@string/accessibility_floating_button_migration_tooltip"
+        android:textSize="@dimen/accessibility_floating_tooltip_font_size"/>
+
+    <View
+        android:id="@+id/arrow_right"
+        android:layout_width="@dimen/accessibility_floating_tooltip_arrow_width"
+        android:layout_height="@dimen/accessibility_floating_tooltip_arrow_height"
+        android:layout_marginLeft="@dimen/accessibility_floating_tooltip_arrow_margin"
+        android:visibility="gone"
+        android:layout_gravity="center_vertical"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index ceba4e3..b99c86f 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -126,8 +126,8 @@
         android:layout_height="wrap_content"
         app:layout_constraintTop_toBottomOf="@id/save"
         app:layout_constraintStart_toStartOf="parent"
-        android:scaleType="matrix"
-        android:visibility="gone"
+        android:scaleType="centerCrop"
+        android:visibility="invisible"
         />
 
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
index 8c54e2c..9e67258 100644
--- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
+++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
@@ -75,7 +75,7 @@
         android:id="@+id/media_logo1"
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size"
-        style="@style/MediaPlayer.AppIcon" />
+        style="@style/MediaPlayer.AppIcon.Recommendation" />
 
     <ImageView
         android:id="@+id/media_cover2"
@@ -91,7 +91,7 @@
         android:id="@+id/media_logo2"
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size"
-        style="@style/MediaPlayer.AppIcon" />
+        style="@style/MediaPlayer.AppIcon.Recommendation" />
 
     <ImageView
         android:id="@+id/media_cover3"
@@ -107,7 +107,7 @@
         android:id="@+id/media_logo3"
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size"
-        style="@style/MediaPlayer.AppIcon" />
+        style="@style/MediaPlayer.AppIcon.Recommendation" />
 
     <ImageView
         android:id="@+id/media_cover4"
@@ -123,7 +123,7 @@
         android:id="@+id/media_logo4"
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size"
-        style="@style/MediaPlayer.AppIcon" />
+        style="@style/MediaPlayer.AppIcon.Recommendation" />
 
     <ImageView
         android:id="@+id/media_cover5"
@@ -139,7 +139,7 @@
         android:id="@+id/media_logo5"
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size"
-        style="@style/MediaPlayer.AppIcon" />
+        style="@style/MediaPlayer.AppIcon.Recommendation" />
 
     <ImageView
         android:id="@+id/media_cover6"
@@ -155,7 +155,7 @@
         android:id="@+id/media_logo6"
         android:layout_width="@dimen/qs_media_icon_size"
         android:layout_height="@dimen/qs_media_icon_size"
-        style="@style/MediaPlayer.AppIcon" />
+        style="@style/MediaPlayer.AppIcon.Recommendation" />
 
     <!-- Long press menu -->
     <TextView
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index f0229a6..a62310b 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -28,7 +28,7 @@
 
     <com.android.systemui.statusbar.policy.Clock
         android:id="@+id/clock"
-        android:layout_width="wrap_content"
+        android:layout_width="0dp"
         android:layout_height="match_parent"
         android:minWidth="48dp"
         android:minHeight="48dp"
@@ -49,17 +49,35 @@
         android:layout_gravity="end|center_vertical"
         android:focusable="false"/>
 
-    <com.android.systemui.statusbar.phone.StatusIconContainer
-        android:id="@+id/statusIcons"
-        android:layout_width="wrap_content"
+    <View
+        android:id="@+id/separator"
+        android:layout_width="0dp"
         android:layout_height="match_parent"
-        android:paddingEnd="@dimen/signal_cluster_battery_padding" />
+        android:layout_gravity="center"
+        android:layout_marginStart="8dp"
+        android:layout_marginEnd="8dp"
+        android:visibility="gone"
+        />
 
-    <com.android.systemui.BatteryMeterView
-        android:id="@+id/batteryRemainingIcon"
+    <LinearLayout
+        android:id="@+id/rightLayout"
+        android:layout_width="0dp"
         android:layout_height="match_parent"
-        android:layout_width="wrap_content"
-        systemui:textAppearance="@style/TextAppearance.QS.Status"
-        android:paddingEnd="2dp" />
+        android:layout_weight="1"
+        >
+        <com.android.systemui.statusbar.phone.StatusIconContainer
+            android:id="@+id/statusIcons"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:paddingEnd="@dimen/signal_cluster_battery_padding" />
 
+        <com.android.systemui.BatteryMeterView
+            android:id="@+id/batteryRemainingIcon"
+            android:layout_height="match_parent"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            systemui:textAppearance="@style/TextAppearance.QS.Status"
+            android:paddingEnd="2dp" />
+
+    </LinearLayout>
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/smart_action_button.xml b/packages/SystemUI/res/layout/smart_action_button.xml
index 2716034..488be3a 100644
--- a/packages/SystemUI/res/layout/smart_action_button.xml
+++ b/packages/SystemUI/res/layout/smart_action_button.xml
@@ -29,6 +29,8 @@
         android:textSize="@dimen/smart_reply_button_font_size"
         android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
         android:textColor="@color/smart_reply_button_text"
+        android:paddingLeft="@dimen/smart_reply_button_action_padding_left"
+        android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
         android:drawablePadding="@dimen/smart_action_button_icon_padding"
         android:textStyle="normal"
         android:ellipsize="none"/>
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index 9faed18..ddf16e0 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -31,5 +31,7 @@
         android:textSize="@dimen/smart_reply_button_font_size"
         android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
         android:textColor="@color/smart_reply_button_text"
+        android:paddingLeft="@dimen/smart_reply_button_padding_horizontal"
+        android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
         android:textStyle="normal"
         android:ellipsize="none"/>
diff --git a/packages/SystemUI/res/layout/smart_reply_view.xml b/packages/SystemUI/res/layout/smart_reply_view.xml
index 9fffc72..9d4d1db 100644
--- a/packages/SystemUI/res/layout/smart_reply_view.xml
+++ b/packages/SystemUI/res/layout/smart_reply_view.xml
@@ -24,8 +24,6 @@
     android:layout_height="wrap_content"
     android:layout_width="wrap_content"
     systemui:spacing="@dimen/smart_reply_button_spacing"
-    systemui:singleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_single_line"
-    systemui:doubleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_double_line"
     systemui:buttonStrokeWidth="@dimen/smart_reply_button_stroke_width">
     <!-- smart_reply_button(s) will be added here. -->
 </com.android.systemui.statusbar.policy.SmartReplyView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index c3c291b..412276d 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -19,8 +19,8 @@
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingStart="4dp"
-        android:paddingEnd="4dp"
+        android:paddingStart="16dp"
+        android:paddingEnd="16dp"
         android:visibility="gone">
     <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
         android:id="@+id/content"
diff --git a/packages/SystemUI/res/layout/wallet_empty_state.xml b/packages/SystemUI/res/layout/wallet_empty_state.xml
index 3ca0f73..cc2e781 100644
--- a/packages/SystemUI/res/layout/wallet_empty_state.xml
+++ b/packages/SystemUI/res/layout/wallet_empty_state.xml
@@ -16,7 +16,8 @@
 ** limitations under the License.
 */
 -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <LinearLayout
         android:id="@+id/wallet_empty_state"
         android:layout_width="match_parent"
@@ -35,6 +36,7 @@
             android:layout_height="28dp"
             android:layout_gravity="center"
             android:layout_marginBottom="8dp"
+            android:tint="?androidprv:attr/colorAccentPrimary"
             android:contentDescription="@null"
             android:scaleType="fitCenter"/>
         <TextView
diff --git a/packages/SystemUI/res/layout/wallet_fullscreen.xml b/packages/SystemUI/res/layout/wallet_fullscreen.xml
index bbb180f..c4939c6 100644
--- a/packages/SystemUI/res/layout/wallet_fullscreen.xml
+++ b/packages/SystemUI/res/layout/wallet_fullscreen.xml
@@ -16,6 +16,8 @@
 -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false">
@@ -65,7 +67,7 @@
             android:paddingVertical="@dimen/wallet_button_vertical_padding"
             android:paddingHorizontal="@dimen/wallet_button_horizontal_padding"
             android:background="@drawable/wallet_action_button_bg"
-            android:textColor="@color/wallet_white"
+            android:textColor="?androidprv:attr/textColorPrimaryInverse"
             android:textAlignment="center"
             android:visibility="gone"/>
 
@@ -83,7 +85,7 @@
             android:paddingHorizontal="@dimen/wallet_button_horizontal_padding"
             android:background="@drawable/wallet_app_button_bg"
             android:text="@string/wallet_app_button_label"
-            android:textColor="@color/GM2_blue_600"
+            android:textColor="?androidprv:attr/colorAccentPrimary"
             android:textAlignment="center"
             android:layout_marginVertical="24dp"/>
 
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index d3ab5b3..e000ff4 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"Mobiele warmkol afgeskakel."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"Mobiele warmkol aangeskakel."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Uitsaai van skerm gestaak."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Werkmodus is onderbreek."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Werkmodus is aan."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"Werkmodus is verander na onderbreek."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Werkmodus is aangeskakel."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Databespaarder is afgeskakel."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Databespaarder is aangeskakel."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g>-limiet"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> waarskuwing"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Werkprofiel"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"Onderbreek"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Aandbeligting"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Aan by sonsondergang"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Tot sonsopkoms"</string>
@@ -473,14 +470,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Volkome\nstilte"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Net\nprioriteit"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Net\nwekkers"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laai tans draadloos • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laai tans • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laai tans vinnig • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laai tans stadig • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Wissel gebruiker, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -676,12 +669,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"Beursie"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Wys alles"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Ontsluit om te betaal"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"Nie opgestel nie"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontsluit om te gebruik"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kon nie jou kaarte kry nie; probeer later weer"</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Sluitskerminstellings"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string>
     <string name="add_tile" msgid="6239678623873086686">"Voeg teël by"</string>
@@ -871,8 +862,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Aan"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Af"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Onbeskikbaar"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"Gedeaktiveer"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigasiebalk"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Uitleg"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra linksknoppie-tipe"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 4dee085..e69ab3f 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"ሙሉ ለሙሉ\nጸጥታ"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"ቅድሚያ ተሰጪ\nብቻ"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"ማንቂያዎች\nብቻ"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በገመድ-አልባ ኃይል በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ኃይል በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በፍጥነት ኃይልን በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • በዝግታ ኃይልን በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"ተጠቃሚ ይለውጡ፣ የአሁን ተጠቃሚ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"የአሁን ተጠቃሚ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index dd342ff..7c8d105 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -475,14 +475,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Potpuna\ntišina"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Samo\npriorit. prekidi"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Samo\nalarmi"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Bežično se puni • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Puni se • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Brzo se puni • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sporo se puni • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Promenite korisnika, aktuelni korisnik je <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Aktuelni korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index adbef20..73efaed 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"একদম\nনিরব"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"শুধুমাত্র\nঅগ্রাধিকার"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"শুধুমাত্র\nঅ্যালার্মগুলি"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ওয়্যারলেস পদ্ধতিতে চার্জ হচ্ছে • পুরো চার্জ হতে <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগবে"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চার্জিং • পুরো চার্জ হতে <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগবে"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • দ্রুত চার্জ হচ্ছে • পুরো চার্জ হতে <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগবে"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ধীরে চার্জ হচ্ছে • পুরো চার্জ হতে <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> লাগবে"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"ব্যবহারকারী পাল্টান, বর্তমান ব্যবহারকারী <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"<xliff:g id="CURRENT_USER_NAME">%s</xliff:g> হল বর্তমান ব্যবহারকারী"</string>
@@ -750,14 +746,10 @@
     <string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"&lt;b&gt;স্ট্যাটাস:&lt;/b&gt; লেভেল কমিয়ে সাইলেন্ করা হয়েছে"</string>
     <string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"&lt;b&gt;স্ট্যাটাস:&lt;/b&gt; র‍্যাঙ্ক বেড়ে গেছে"</string>
     <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;স্ট্যাটাস:&lt;/b&gt; র‍্যাঙ্ক কমে গেছে"</string>
-    <!-- no translation found for notification_channel_summary_priority_baseline (46674690072551234) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_bubble (1275413109619074576) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_dnd (6665395023264154361) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_all (7151752959650048285) -->
-    <skip />
+    <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয়"</string>
+    <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয়, বাবল হিসেবেও এটি দেখা যায়"</string>
+    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয় এবং এর ফলে \'বিরক্ত করবে না\' মোডে কাজ করতে অসুবিধা হয়"</string>
+    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয়, বাবল হিসেবেও এটি দেখা যায় এবং এর ফলে \'বিরক্ত করবে না\' মোডে কাজ করতে অসুবিধা হয়"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"সেটিংস"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ কথোপকথন ফিচার কাজ করে না"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index a54dffe..5c9ec89 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -475,14 +475,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Potpuna\ntišina"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Samo\nprioritetni prekidi"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Samo\nalarmi"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Bežično punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Brzo punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sporo punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Zamijeni korisnika. Trenutni korisnik je <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Trenutni korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 803bbd1..fc3b2f5 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Silenci\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Només\ninterr. prior."</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Només\nalarmes"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregant sense fil • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • S\'està carregant • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregant ràpidament • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregant lentament • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Canvia d\'usuari. Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 8ed760a..4560cad 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -477,14 +477,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Úplné\nticho"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Pouze\nprioritní"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Pouze\nbudíky"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Bezdrátové nabíjení • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíjení • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Rychlé nabíjení • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Pomalé nabíjení • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Přepnout uživatele, aktuální uživatel: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Aktuální uživatel <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c76ebc3..a30e0636 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"Mobilhotspot er slået fra."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"Mobilhotspot er slået til."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Casting af din skærm er stoppet."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Arbejdstilstand er på pause."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Arbejdstilstand er slået til."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"Arbejdstilstand er sat på pause."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Arbejdstilstand er slået til."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Datasparefunktionen er slået fra."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Datasparefunktionen er aktiveret."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Grænse: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Advarsel ved <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Arbejdsprofil"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"Sat på pause"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nattelys"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Tænd ved solnedgang"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Indtil solopgang"</string>
@@ -473,14 +470,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Total\nstilhed"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Kun\nprioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Kun\nalarmer"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Trådløs opladning • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader hurtigt • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader langsomt • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Skift bruger. Nuværende bruger er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Nuværende bruger: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -676,12 +669,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Vis alle"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Lås op for at betale"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"Ikke konfigureret"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Lås op for at bruge"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Dine kort kunne ikke hentes. Prøv igen senere."</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lås skærmindstillinger"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string>
     <string name="add_tile" msgid="6239678623873086686">"Tilføj et felt"</string>
@@ -871,8 +862,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Til"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Fra"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Ikke tilgængelig"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"Deaktiveret"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigationslinje"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Ekstra venstre knaptype"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3da19fc..fd8af9d 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Πλήρης\nσίγαση"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Μόνο\nπροτεραιότητας"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Μόνο\nειδοποιήσεις"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ασύρματη φόρτιση • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Φόρτιση • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Γρήγορη φόρτιση • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Αργή φόρτιση • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Εναλλαγή χρήστη, τρέχων χρήστης <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Τρέχων χρήστης <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 15347dd..58a31df 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"Zona móvil desactivada"</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"Zona móvil activada"</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Transmisión de pantalla detenida"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Modo de trabajo pausado."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Modo de trabajo activado"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"Se pausó el modo de trabajo."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Se activó el modo de trabajo."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Se desactivó el Ahorro de datos."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Se activó el Ahorro de datos."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Límite de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Perfil de trabajo"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"Pausado"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Luz nocturna"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Al atardecer"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Hasta el amanecer"</string>
@@ -473,14 +470,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Silencio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Solo\nprioridad"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Solo\nalarmas"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando de manera inalámbrica • Se completará en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • Se completará en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando rápido • Se completará en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lento • Se completará en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Cambiar de usuario (usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"El usuario actual es <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -676,12 +669,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar todo"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Desbloquear para pagar"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"Sin configurar"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocurrió un problema al obtener las tarjetas; vuelve a intentarlo más tarde"</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configuración de pantalla de bloqueo"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avión"</string>
     <string name="add_tile" msgid="6239678623873086686">"Agregar mosaico"</string>
@@ -871,8 +862,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Activado"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desactivado"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"No disponible"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"Inhabilitada"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegación"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Diseño"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botón izquierdo adicional"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 57ce1c5..a863111 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Silencio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Solo\ncon prioridad"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Solo\nalarmas"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga sin cables • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga rápida • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • En <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> terminará de cargarse"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Cambiar de usuario (usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 85679b9..932ce3e 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Isiltasun\nosoa"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Lehentasunezkoak\nsoilik"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Alarmak\nsoilik"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hari gabe kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Bizkor kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mantso kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Aldatu erabiltzailea. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita daukana."</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Erabiltzailea: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 052a87a..89b4fbd 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"نقطه اتصال دستگاه همراه خاموش شد."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"نقطه اتصال دستگاه همراه روشن شد."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"فرستادن صفحه نمایش متوقف شد."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"حالت کار موقتاً متوقف شده است."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"حالت کار روشن."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"حالت کار موقتاً متوقف شد."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"حالت کار روشن شد."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"صرفه‌جویی داده خاموش شد."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"صرفه‌جویی داده روشن شد."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> محدودیت"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"هشدار <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"نمایه کاری"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"موقتاً متوقف"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"نور شب"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"غروب روشن می‌شود"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"تا طلوع"</string>
@@ -473,14 +470,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"سکوت\nکامل"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"فقط\nاولویت‌دار"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"فقط\nهشدارها"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • درحال شارژ کردن بی‌سیم • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • درحال شارژ کردن • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • درحال شارژ کردن سریع • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • درحال شارژ کردن آهسته • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"تعویض کاربر، کاربر کنونی <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"کاربر کنونی <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -676,12 +669,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"کیف‌پول"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"نمایش همه"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"باز کردن قفل برای پرداخت"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"تنظیم‌نشده"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"برای استفاده، قفل را باز کنید"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"هنگام دریافت کارت‌ها مشکلی پیش آمد، لطفاً بعداً دوباره امتحان کنید"</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"تنظیمات صفحه قفل"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"نمایه کاری"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"حالت هواپیما"</string>
     <string name="add_tile" msgid="6239678623873086686">"افزودن کاشی"</string>
@@ -871,8 +862,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"روشن"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"خاموش"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"در دسترس نیست"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"غیرفعال"</string>
     <string name="nav_bar" msgid="4642708685386136807">"نوار پیمایش"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"طرح‌بندی"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"نوع دکمه منتهی‌الیه چپ"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index efe1833..a9acd50 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Aucune\ninterruption"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Priorité\nuniquement"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Alarmes\nuniquement"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge sans fil • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge rapide • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge lente • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Changer d\'utilisateur (utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index d5da5d5..083435bf 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Silencio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Só\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Só\nalarmas"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando sen fíos • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando rapidamente • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando lentamente • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Cambiar usuario, usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 7e92ccf..99d3af6 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -750,14 +750,10 @@
     <string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"&lt;b&gt;સ્ટેટસ:&lt;/b&gt; સાઇલન્ટ પર અવનત કરવામાં આવ્યું"</string>
     <string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"&lt;b&gt;સ્ટેટસ:&lt;/b&gt; ઉપલી રેંક આપવામાં આવી"</string>
     <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;સ્ટેટસ:&lt;/b&gt; નીચલી રેંક આપવામાં આવી"</string>
-    <!-- no translation found for notification_channel_summary_priority_baseline (46674690072551234) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_bubble (1275413109619074576) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_dnd (6665395023264154361) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_all (7151752959650048285) -->
-    <skip />
+    <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે"</string>
+    <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે, બબલ તરીકે દેખાય છે"</string>
+    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે, ખલેલ પાડશો નહીં મોડમાં વિક્ષેપ ઊભો કરે છે"</string>
+    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે, બબલ તરીકે દેખાય છે, ખલેલ પાડશો નહીં મોડમાં વિક્ષેપ ઊભો કરે છે"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"સેટિંગ"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"પ્રાધાન્યતા"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીતની સુવિધાઓને સપોર્ટ આપતી નથી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index cfe2079..b526ff6 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"पूरी तरह\nशांत"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"केवल\nप्राथमिकता"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"केवल\nअलार्म"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • वायरलेस तरीके से चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • तेज़ चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • धीरे चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"उपयोगकर्ता बदलें, मौजूदा उपयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"मौजूदा उपयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 9246023..fedeb77 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -475,14 +475,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Potpuna\ntišina"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Samo\nprioritetno"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Samo\nalarmi"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • bežično punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • brzo punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • sporo punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Promjena korisnika, trenutačni korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Trenutačan korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 3cfbaba..d3bd516 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Teljes\nnémítás"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Csak\nprioritás"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Csak\nriasztások"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Vezeték nélküli töltés • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Töltés • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Gyors töltés • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lassú töltés • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Felhasználóváltás (a jelenlegi felhasználó: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Jelenlegi felhasználó (<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 4295b96..22feecfc 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Algjör\nþögn"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Aðeins\nforgangur"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Aðeins\nvekjarar"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Þráðlaus hleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Í hleðslu • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hraðhleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Hæg hleðsla • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Skipta um notanda; núverandi notandi er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Núverandi notandi er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 78b85c9..6cc699b 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Silenzio\ntotale"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Solo con\npriorità"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Solo\nsveglie"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • In carica wireless • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • In carica • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ricarica veloce • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ricarica lenta • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Cambia utente, utente corrente <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Utente corrente <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 39abcde..0e331de 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"サイレント\n"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"重要な\n通知のみ"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"アラーム\nのみ"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ワイヤレス充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 急速充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 低速充電中 • 完了まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ユーザーを切り替える"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"ユーザーを切り替える、現在のユーザーは<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"現在のユーザー: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 78f228a..fddf305 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"ស្ងៀមស្ងាត់\nទាំងស្រុង"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"អាទិភាព\nប៉ុណ្ណោះ"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"សំឡេងរោទ៍\nប៉ុណ្ណោះ"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្មឥតខ្សែ • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្ម • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុង​សាកថ្មយ៉ាង​ឆាប់រហ័ស • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុង​សាកថ្ម​យឺត • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរ​អ្នក​ប្រើ"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"ប្ដូរ​អ្នកប្រើ ​អ្នកប្រើ​បច្ចុប្បន្ន <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"អ្នកប្រើបច្ចុប្បន្ន <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 3cb20af..8d542ddf 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"ಮೊಬೈಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"ಮೊಬೈಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"ಸ್ಕ್ರೀನ್ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಲಾಗಿದೆ."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"ಕೆಲಸದ ಮೋಡ್ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"ಕೆಲಸದ ಮೋಡ್ ಆನ್ ಆಗಿದೆ."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"ಕೆಲಸದ ಮೋಡ್ ಅನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"ಕೆಲಸದ ಮೋಡ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"ಡೇಟಾ ಸೇವರ್ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"ಡೇಟಾ ಸೇವರ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಮಿತಿ"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"ನೈಟ್ ಲೈಟ್"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ಸೂರ್ಯಾಸ್ತದಲ್ಲಿ"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ಸೂರ್ಯೋದಯದವರೆಗೆ"</string>
@@ -676,12 +673,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"ವಾಲೆಟ್"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"ಎಲ್ಲವನ್ನೂ ತೋರಿಸಿ"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"ಪಾವತಿಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"ಇನ್ನೂ ಸೆಟಪ್‌ ಮಾಡಿಲ್ಲ"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ಬಳಸಲು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"ನಿಮ್ಮ ಕಾರ್ಡ್‌ಗಳನ್ನು ಪಡೆಯುವಾಗ ಸಮಸ್ಯೆ ಉಂಟಾಗಿದೆ, ನಂತರ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"ಲಾಕ್ ಸ್ಕ್ರ್ರೀನ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
     <string name="add_tile" msgid="6239678623873086686">"ಟೈಲ್ ಸೇರಿಸಿ"</string>
@@ -871,8 +866,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"ಆನ್"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"ಆಫ್"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"ಲಭ್ಯವಿಲ್ಲ"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="nav_bar" msgid="4642708685386136807">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"ಲೇಔಟ್"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"ಹೆಚ್ಚುವರಿ ಎಡ ಬಟನ್ ವಿಧ"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 91bdc6e..5d70e13 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"ຄວາມ​ງຽບ\nທັງ​ໝົດ"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"ບຸ​ລິ​ມະ​ສິດ\nເທົ່າ​ນັ້ນ"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"ໂມງ​ປຸກ\nເທົ່າ​ນັ້ນ"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟແບບໄຮ້ສາຍ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟແບບໄວ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟແບບຊ້າ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"ປ່ຽນຜູ່ໃຊ້, ຜູ່ໃຊ້ປະຈຸບັນ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"ຜູ້ໃຊ້ປະຈຸບັນ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 407db29..fdb8c10 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -477,14 +477,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Visiška\ntyla"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Tik\nprioritetiniai"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Tik\nsignalai"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Įkraunama be laidų • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Įkraunama • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Sparčiai įkraunama • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lėtai įkraunama • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Perjungti naudotoją"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Perjungti naudotoją, dabartinis naudotojas <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Dabartinis naudotojas <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index c4524f3..fdb76bb 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Целосна\nтишина"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Само\nприоритетни"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Само\nаларми"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни безжично • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни брзо • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни бавно • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Промени го корисникот, тековен корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Тековен корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 7001a1a..8d3dffd 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Дуугүй\nболгох"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Зөвхөн\nхамгийн чухлыг"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Зөвхөн\nсэрүүлэг"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Утасгүй цэнэглэж байна • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Цэнэглэж байна • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Хурдтай цэнэглэж байна • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Удаан цэнэглэж байна • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Хэрэглэгчийг сэлгэх, одоогийн хэрэглэгч <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Одоогийн хэрэглэгч <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 837d900..267b74a 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"Tempat liputan mudah alih bergerak dimatikan."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"Tempat liputan mudah alih bergerak dihidupkan."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Penghantaran skrin dihentikan."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Mod kerja dijeda."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Mod kerja hidup."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"Mod kerja dijeda."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Mod kerja dihidupkan."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Penjimat Data dimatikan."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Penjimat Data dihidupkan."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> had"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Profil kerja"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"Dijeda"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Cahaya Malam"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Dihidupkan pd senja"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Hingga matahari terbit"</string>
@@ -676,12 +673,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Tunjukkan semua"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Buka kunci untuk membayar"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"Tidak disediakan"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Buka kunci untuk menggunakan"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Terdapat masalah sewaktu mendapatkan kad anda. Sila cuba sebentar lagi"</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Tetapan skrin kunci"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mod pesawat"</string>
     <string name="add_tile" msgid="6239678623873086686">"Tambahkan jubin"</string>
@@ -871,8 +866,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Hidup"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Mati"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Tidak tersedia"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"Dilumpuhkan"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Bar navigasi"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Reka letak"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Jenis butang kiri tambahan"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index fa6e62e..cf82ea4 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Total\nstillhet"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Bare\nPrioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Bare\nalarmer"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lader trådløst • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lader • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lader raskt • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lader sakte • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Bytt bruker, gjeldende bruker er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Gjeldende bruker: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 26412ce..be1735c 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"Mobiele hotspot staat uit."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"Mobiele hotspot staat aan."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Casten van scherm gestopt."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Werkmodus is onderbroken."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Werkmodus aan."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"Werkmodus is uitgezet."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Werkmodus staat aan."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Databesparing staat uit."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Databesparing staat aan."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limiet van <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Waarschuwing voor <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Werkprofiel"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"Onderbroken"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nachtverlichting"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Aan bij zonsondergang"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Tot zonsopgang"</string>
@@ -473,14 +470,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Totale\nstilte"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Alleen\nprioriteit"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Alleen\nalarmen"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Draadloos opladen • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Opladen • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Snel opladen • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Langzaam opladen • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Schakelen tussen gebruikers, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -676,12 +669,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"Wallet"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Alles tonen"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Ontgrendelen om te betalen"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"Niet ingesteld"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Ontgrendelen om te gebruiken"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Er is een probleem opgetreden bij het ophalen van je kaarten. Probeer het later opnieuw."</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Instellingen voor vergrendelscherm"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string>
     <string name="add_tile" msgid="6239678623873086686">"Tegel toevoegen"</string>
@@ -871,8 +862,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Aan"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Uit"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Niet beschikbaar"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"Uit"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigatiebalk"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Lay-out"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Extra knoptype links"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 268c245..9a2cd80 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"ସମ୍ପୂର୍ଣ୍ଣ\nନୀରବ"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"କେବଳ\nପ୍ରାଥମିକତା"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"କେବଳ\nଆଲାର୍ମ"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ୱାୟାରଲେସ୍ ଭାବେ ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଶୀଘ୍ର ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଧୀରେ ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍‍ ବଦଳାନ୍ତୁ"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"ୟୁଜର୍‍ ବଦଳାନ୍ତୁ, ବର୍ତ୍ତମାନର ୟୁଜର୍‍ ହେଉଛନ୍ତି <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"ବର୍ତ୍ତମାନର ୟୁଜର୍‍ ହେଉଛନ୍ତି <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -750,14 +746,10 @@
     <string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"&lt;b&gt;ସ୍ଥିତି:&lt;/b&gt; ନୀରବକୁ ଡିମୋଟ୍ କରାଯାଇଛି"</string>
     <string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"&lt;b&gt;ସ୍ଥିତି:&lt;/b&gt; ରେଙ୍କ ଉପରକୁ କରାଯାଇଛି"</string>
     <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;ସ୍ଥିତି:&lt;/b&gt; ରେଙ୍କ ତଳକୁ କରାଯାଇଛି"</string>
-    <!-- no translation found for notification_channel_summary_priority_baseline (46674690072551234) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_bubble (1275413109619074576) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_dnd (6665395023264154361) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_all (7151752959650048285) -->
-    <skip />
+    <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ"</string>
+    <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ, ଏକ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ"</string>
+    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ, \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\'କୁ ବାଧା ଦିଏ"</string>
+    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ, ଏକ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ, \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\'କୁ ବାଧା ଦିଏ"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ସେଟିଂସ୍"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ପ୍ରାଥମିକତା"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ଫିଚରଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 635cb2f..bc9b2ee 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -750,14 +750,10 @@
     <string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"&lt;b&gt;ਸਥਿਤੀ:&lt;/b&gt; ਦਰਜਾ ਘਟਾ ਕੇ ਸ਼ਾਂਤ \'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
     <string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"&lt;b&gt;ਸਥਿਤੀ:&lt;/b&gt; ਦਰਜਾ ਵਧਾਇਆ ਗਿਆ"</string>
     <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;ਸਥਿਤੀ:&lt;/b&gt; ਦਰਜਾ ਘਟਾਇਆ ਗਿਆ"</string>
-    <!-- no translation found for notification_channel_summary_priority_baseline (46674690072551234) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_bubble (1275413109619074576) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_dnd (6665395023264154361) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_all (7151752959650048285) -->
-    <skip />
+    <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਵਜੋਂ ਦਿਖਾਉਂਦਾ ਹੈ"</string>
+    <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ, ਬਬਲ ਵਜੋਂ ਦਿਖਾਉਂਦਾ ਹੈ"</string>
+    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਵਜੋਂ ਦਿਖਾਉਂਦਾ ਹੈ, \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਸੁਵਿਧਾ ਵਿੱਚ ਵੀ ਵਿਘਨ ਪੈ ਸਕਦਾ ਹੈ"</string>
+    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ, ਬਬਲ ਵਜੋਂ ਦਿਖਾਉਂਦਾ ਹੈ, \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਸੁਵਿਧਾ ਵਿੱਚ ਵੀ ਵਿਘਨ ਪੈ ਸਕਦਾ ਹੈ"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਗੱਲਬਾਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 6ee7453..3c6578e 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -477,14 +477,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Całkowita\ncisza"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Tylko\npriorytetowe"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Tylko\nalarmy"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ładowanie bezprzewodowe • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Szybkie ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wolne ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Przełącz użytkownika. Bieżący użytkownik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Bieżący użytkownik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index b15a144..8228c0c 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"O ponto de acesso móvel foi desativado."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"O ponto de acesso móvel foi ativado."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"A transmissão de tela foi interrompida."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Modo de trabalho pausado."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Modo de trabalho ativado."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"O modo de trabalho foi pausado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Modo de trabalho ativado."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Economia de dados desativada."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Economia de dados ativada."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limite: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Perfil de trabalho"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"Pausado"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Modo noturno"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ativ. ao pôr do sol"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Até o nascer do sol"</string>
@@ -473,14 +470,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Silêncio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Somente\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Somente\nalarmes"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando sem fio • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga rápida • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Alternar usuário. Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -676,12 +669,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar tudo"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Desbloqueie para pagar"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"Dispositivos não configurados"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configurações de tela de bloqueio"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string>
     <string name="add_tile" msgid="6239678623873086686">"Adicionar bloco"</string>
@@ -871,8 +862,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Ativado"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desativado"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Indisponível"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"Desativado"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegação"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botão esquerdo extra"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 90b1931..afebc31 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Silêncio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Apenas\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Apenas\nalarmes"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar sem fios • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar rapidamente • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar lentamente • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mudar utilizador"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Mudar de utilizador; o utilizador atual é <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Utilizador atual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index b15a144..8228c0c 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"O ponto de acesso móvel foi desativado."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"O ponto de acesso móvel foi ativado."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"A transmissão de tela foi interrompida."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Modo de trabalho pausado."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Modo de trabalho ativado."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"O modo de trabalho foi pausado."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Modo de trabalho ativado."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Economia de dados desativada."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Economia de dados ativada."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limite: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Perfil de trabalho"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"Pausado"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Modo noturno"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ativ. ao pôr do sol"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Até o nascer do sol"</string>
@@ -473,14 +470,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Silêncio\ntotal"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Somente\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Somente\nalarmes"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando sem fio • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga rápida • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carga lenta • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Alternar usuário. Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -676,12 +669,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"Carteira"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Mostrar tudo"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Desbloqueie para pagar"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"Dispositivos não configurados"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para usar"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao carregar os cards. Tente novamente mais tarde"</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Configurações de tela de bloqueio"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string>
     <string name="add_tile" msgid="6239678623873086686">"Adicionar bloco"</string>
@@ -871,8 +862,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Ativado"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Desativado"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Indisponível"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"Desativado"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Barra de navegação"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Layout"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Tipo de botão esquerdo extra"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 44325f7..407ad62 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"Mobilný hotspot je vypnutý."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"Mobilný hotspot je zapnutý."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Prenášanie bolo zastavené."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Pracovný režim je pozastavený."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Pracovný režim zapnutý"</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"Pracovný režim bol pozastavený."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Pracovný režim je zapnutý."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Šetrič dát bol vypnutý."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Šetrič dát bol zapnutý."</string>
@@ -416,8 +414,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limit: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Upozornenie pri <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Pracovný profil"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"Pozastavené"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nočný režim"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Zapne sa pri západe slnka"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do východu slnka"</string>
@@ -477,14 +474,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Úplné\nticho"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Iba\nprioritné"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Iba\nbudíky"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíja sa bezdrôtovo • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíja sa • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíja sa rýchlo • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíja sa pomaly • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Prepnúť používateľa (súčasný používateľ: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Aktuálny používateľ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -682,12 +675,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"Peňaženka"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Zobraziť všetko"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Odomknúť a zaplatiť"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"Nenastavené"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Odomknúť a použiť"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Pri načítavaní kariet sa vyskytol problém. Skúste to neskôr."</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Nastavenia uzamknutej obrazovky"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Pracovný profil"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Režim v lietadle"</string>
     <string name="add_tile" msgid="6239678623873086686">"Pridať dlaždicu"</string>
@@ -881,8 +872,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Zapnuté"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Vypnuté"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Nedostupné"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"Deaktivované"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Navigačný panel"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Rozloženie"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Dodatočný typ ľavého tlačidla"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 70b53cb..d44bd22 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Heshtje\ne plotë"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Vetëm\nme prioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Vetëm\nalarmet"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet me valë • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet shpejt • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet ngadalë • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Ndërro përdoruesin. Përdoruesi aktual është <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Përdoruesi aktual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -750,14 +746,10 @@
     <string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"&lt;b&gt;Statusi:&lt;/b&gt; Ulur në nivel si në heshtje"</string>
     <string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"&lt;b&gt;Statusi:&lt;/b&gt; Renditur më lart"</string>
     <string name="notification_channel_summary_automatic_demoted" msgid="1831303964660807700">"&lt;b&gt;Statusi:&lt;/b&gt; Renditur më poshtë"</string>
-    <!-- no translation found for notification_channel_summary_priority_baseline (46674690072551234) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_bubble (1275413109619074576) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_dnd (6665395023264154361) -->
-    <skip />
-    <!-- no translation found for notification_channel_summary_priority_all (7151752959650048285) -->
-    <skip />
+    <string name="notification_channel_summary_priority_baseline" msgid="46674690072551234">"Shfaqet në krye të njoftimeve të bisedës dhe si fotografia e profilit në ekranin e kyçjes"</string>
+    <string name="notification_channel_summary_priority_bubble" msgid="1275413109619074576">"Shfaqet në krye të njoftimeve të bisedës, shfaqet si fotografia e profilit në ekranin e kyçjes dhe shfaqet si flluskë"</string>
+    <string name="notification_channel_summary_priority_dnd" msgid="6665395023264154361">"Shfaqet në krye të njoftimeve të bisedës, shfaqet si fotografia e profilit në ekranin e kyçjes dhe ndërpret modalitetin \"Mos shqetëso\""</string>
+    <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shfaqet në krye të njoftimeve të bisedës dhe si fotografia e profilit në ekranin e kyçjes, shfaqet si flluskë dhe ndërpret modalitetin \"Mos shqetëso\""</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cilësimet"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Përparësia"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet veçoritë e bisedës"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index de1c9a4..93fb30f 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -475,14 +475,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Потпуна\nтишина"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Само\nприорит. прекиди"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Само\nаларми"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Бежично се пуни • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Пуни се • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Брзо се пуни • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Споро се пуни • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Замени корисника"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Промените корисника, актуелни корисник је <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Актуелни корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index fcbe07d..3e7e1b1 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -473,14 +473,10 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Helt\ntyst"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Endast\nprioriterade"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Endast\nalarm"</string>
-    <!-- no translation found for keyguard_indication_charging_time_wireless (577856646141738675) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time (6492711711891071502) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_fast (8390311020603859480) -->
-    <skip />
-    <!-- no translation found for keyguard_indication_charging_time_slowly (301936949731705417) -->
-    <skip />
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas trådlöst • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="8390311020603859480">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas snabbt • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="301936949731705417">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas långsamt • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="5759855008166759399">"Byt användare. Aktuell användare: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"Aktuell användare <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1c70acc..0ec4a4b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -289,11 +289,9 @@
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"I-hotspot ivaliwe."</string>
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"I-hotspot ivuliwe."</string>
     <string name="accessibility_casting_turned_off" msgid="1387906158563374962">"Ukusakaza kwesikrini kumisiwe."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_off (9106217884005620744) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_off" msgid="9106217884005620744">"Imodi yokusebenza imisiwe."</string>
     <string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"Imodi yomsebenzi ivuliwe."</string>
-    <!-- no translation found for accessibility_quick_settings_work_mode_changed_off (2653550342355027441) -->
-    <skip />
+    <string name="accessibility_quick_settings_work_mode_changed_off" msgid="2653550342355027441">"Imodi yokusebenza imisiwe."</string>
     <string name="accessibility_quick_settings_work_mode_changed_on" msgid="1105258550138313384">"Imodi yomsebenzi ivuliwe."</string>
     <string name="accessibility_quick_settings_data_saver_changed_off" msgid="4910847127871603832">"Iseva yedatha ivaliwe."</string>
     <string name="accessibility_quick_settings_data_saver_changed_on" msgid="6370606590802623078">"Iseva yedatha ivuliwe."</string>
@@ -412,8 +410,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> umkhawulo"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> isexwayiso"</string>
     <string name="quick_settings_work_mode_label" msgid="2754212289804324685">"Iphrofayela yomsebenzi"</string>
-    <!-- no translation found for quick_settings_work_mode_paused (4841109346916998613) -->
-    <skip />
+    <string name="quick_settings_work_mode_paused" msgid="4841109346916998613">"Kumisiwe"</string>
     <string name="quick_settings_night_display_label" msgid="8180030659141778180">"Ukukhanya kwasebusuku"</string>
     <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Kuvulwe ekushoneni kwelanga"</string>
     <string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Kuze kube sekuphumeni kwelanga"</string>
@@ -676,12 +673,10 @@
     <string name="wallet_title" msgid="5369767670735827105">"I-wallet"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Bonisa konke"</string>
     <string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"Vula ukuze ukhokhele"</string>
-    <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
-    <skip />
+    <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"Akusethiwe"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Vula ukuze usebenzise"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"Kube khona inkinga yokuthola amakhadi akho, sicela uzame futhi ngemuva kwesikhathi"</string>
-    <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
-    <skip />
+    <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Amasethingi okukhiya isikrini"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Iphrofayela yomsebenzi"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Imodi yendiza"</string>
     <string name="add_tile" msgid="6239678623873086686">"Engeza ithayili"</string>
@@ -871,8 +866,7 @@
     <string name="switch_bar_on" msgid="1770868129120096114">"Vuliwe"</string>
     <string name="switch_bar_off" msgid="5669805115416379556">"Valiwe"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Akutholakali"</string>
-    <!-- no translation found for tile_disabled (373212051546573069) -->
-    <skip />
+    <string name="tile_disabled" msgid="373212051546573069">"Kukhutshaziwe"</string>
     <string name="nav_bar" msgid="4642708685386136807">"Ibha yokuzula"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Isakhiwo"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Uhlobo lwenkinobho engakwesokunxele engeziwe"</string>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index eb72442..067d56f 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -131,8 +131,6 @@
 
     <declare-styleable name="SmartReplyView">
         <attr name="spacing" format="dimension" />
-        <attr name="singleLineButtonPaddingHorizontal" format="dimension" />
-        <attr name="doubleLineButtonPaddingHorizontal" format="dimension" />
         <attr name="buttonStrokeWidth" format="dimension" />
     </declare-styleable>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 08a2e19..8d2a82c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -286,7 +286,5 @@
     <color name="accessibility_floating_menu_stroke_dark">#26FFFFFF</color> <!-- 15% -->
 
     <!-- Wallet screen -->
-    <color name="wallet_white">#FFFFFF</color>
     <color name="wallet_card_border">#33FFFFFF</color>
-    <color name="wallet_primary_text">@color/GM2_grey_900</color>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c60ec78..7e56063 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -151,7 +151,7 @@
     <dimen name="notification_max_heads_up_height_before_s">162dp</dimen>
 
     <!-- Height of a heads up notification in the status bar -->
-    <dimen name="notification_max_heads_up_height">132dp</dimen>
+    <dimen name="notification_max_heads_up_height">143dp</dimen>
 
     <!-- Height of a heads up notification in the status bar -->
     <dimen name="notification_max_heads_up_height_increased">188dp</dimen>
@@ -1147,15 +1147,14 @@
     <!-- Smart reply button. Total height 48dp, visible height 32dp. -->
     <dimen name="smart_reply_button_spacing">8dp</dimen>
     <dimen name="smart_reply_button_padding_vertical">14dp</dimen>
-    <!-- Note: The following two paddings need to be different until b/78876518 is fixed. -->
-    <dimen name="smart_reply_button_padding_horizontal_single_line">20dp</dimen>
-    <dimen name="smart_reply_button_padding_horizontal_double_line">19dp</dimen>
+    <dimen name="smart_reply_button_padding_horizontal">16dp</dimen>
+    <dimen name="smart_reply_button_action_padding_left">8dp</dimen>
     <dimen name="smart_reply_button_min_height">48dp</dimen>
     <dimen name="smart_reply_button_stroke_width">1dp</dimen>
     <dimen name="smart_reply_button_font_size">14sp</dimen>
     <dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
     <!-- Corner radius = half of min_height to create rounded sides. -->
-    <dimen name="smart_reply_button_corner_radius">24dp</dimen>
+    <dimen name="smart_reply_button_corner_radius">8dp</dimen>
     <dimen name="smart_action_button_icon_size">18dp</dimen>
     <dimen name="smart_action_button_icon_padding">8dp</dimen>
 
@@ -1199,7 +1198,7 @@
         0
     </item>
     <!-- Ending text size in sp of batteryLevel for wireless charging animation -->
-    <item name="wireless_charging_anim_battery_level_text_size_end" format="float" type="dimen">24
+    <item name="wireless_charging_anim_battery_level_text_size_end" format="float" type="dimen">48
     </item>
     <!-- time until battery info is at full opacity-->
     <integer name="wireless_charging_anim_opacity_offset">80</integer>
@@ -1443,6 +1442,15 @@
     <dimen name="accessibility_floating_menu_large_single_radius">33dp</dimen>
     <dimen name="accessibility_floating_menu_large_multiple_radius">35dp</dimen>
 
+    <dimen name="accessibility_floating_tooltip_arrow_width">8dp</dimen>
+    <dimen name="accessibility_floating_tooltip_arrow_height">16dp</dimen>
+    <dimen name="accessibility_floating_tooltip_arrow_margin">-2dp</dimen>
+    <dimen name="accessibility_floating_tooltip_arrow_corner_radius">2dp</dimen>
+    <dimen name="accessibility_floating_tooltip_text_corner_radius">8dp</dimen>
+    <dimen name="accessibility_floating_tooltip_margin">16dp</dimen>
+    <dimen name="accessibility_floating_tooltip_padding">16dp</dimen>
+    <dimen name="accessibility_floating_tooltip_font_size">14sp</dimen>
+
     <dimen name="rounded_slider_height">48dp</dimen>
     <!-- rounded_slider_height / 2 -->
     <dimen name="rounded_slider_corner_radius">24dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 30add20..150fc73 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -689,12 +689,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on">Mobile hotspot turned on.</string>
     <!-- Announcement made when the screen stopped casting (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_casting_turned_off">Screen casting stopped.</string>
-    <!-- Content description of the work mode title in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <!-- Content description of the work mode title in quick settings when off (not shown on the screen). Paused is used as an adjective [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_work_mode_off">Work mode paused.</string>
     <!-- Content description of the work mode title in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_work_mode_on">Work mode on.</string>
-    <!-- Announcement made when the work mode changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_work_mode_changed_off">Work mode turned paused.</string>
+    <!-- Announcement made when the work mode changes to off (not shown on the screen). Paused is used as a verb. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_work_mode_changed_off">Work mode paused.</string>
     <!-- Announcement made when the work mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_work_mode_changed_on">Work mode turned on.</string>
     <!-- Announcement made when the Data Saver changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -2828,7 +2828,7 @@
     <!-- Label for button to go to media control settings screen [CHAR_LIMIT=30] -->
     <string name="controls_media_settings_button">Settings</string>
 
-    <!-- Title for Smartspace recommendation card within media controls [CHAR_LIMIT=50] -->
+    <!-- Title for Smartspace recommendation card within media controls. The "Play" means the action to play a media [CHAR_LIMIT=10] -->
     <string name="controls_media_smartspace_rec_title">Play</string>
 
     <!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 10f7e40..9fa63dd 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -660,9 +660,12 @@
         <item name="android:tint">?android:attr/colorAccent</item>
     </style>
 
+    <style name="MediaPlayer.AppIcon.Recommendation" parent="MediaPlayer.AppIcon">
+        <item name="android:tint">@color/transparent</item>
+    </style>
+
     <style name="MediaPlayer.Album">
         <item name="android:backgroundTint">@color/media_player_album_bg</item>
-
     </style>
 
     <!-- Used to style charging animation AVD animation -->
@@ -692,6 +695,7 @@
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowLightStatusBar">true</item>
         <item name="android:windowLightNavigationBar">true</item>
+        <item name="android:windowActivityTransitions">true</item>
     </style>
 
     <!-- Privacy dialog -->
@@ -874,12 +878,12 @@
 
     <style name="Wallet.TextAppearance">
       <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-      <item name="android:textColor">@color/wallet_primary_text</item>
+      <item name="android:textColor">?android:attr/textColorPrimary</item>
       <item name="android:singleLine">true</item>
       <item name="android:textSize">14sp</item>
     </style>
 
-    <style name="Wallet.Theme">
-      <item name="android:colorControlHighlight">@*android:color/primary_text_material_dark</item>
+    <style name="Wallet.Theme" parent="@android:style/Theme.DeviceDefault">
+      <item name="android:colorBackground">@android:color/system_neutral1_900</item>
     </style>
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
index 7cd7c9e..74aa138 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java
@@ -16,9 +16,6 @@
 
 package com.android.systemui.shared.pip;
 
-import static android.graphics.Matrix.MSCALE_X;
-import static android.graphics.Matrix.MSCALE_Y;
-
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -32,15 +29,17 @@
  * source of truth on enabling/disabling and the actual value of corner radius.
  */
 public class PipSurfaceTransactionHelper {
-    /** corner radius is currently disabled. */
-    private final float mCornerRadius = 0f;
-
+    private final int mCornerRadius;
     private final Matrix mTmpTransform = new Matrix();
     private final float[] mTmpFloat9 = new float[9];
     private final RectF mTmpSourceRectF = new RectF();
     private final RectF mTmpDestinationRectF = new RectF();
     private final Rect mTmpDestinationRect = new Rect();
 
+    public PipSurfaceTransactionHelper(int cornerRadius) {
+        mCornerRadius = cornerRadius;
+    }
+
     public PictureInPictureSurfaceTransaction scale(
             SurfaceControl.Transaction tx, SurfaceControl leash,
             Rect sourceBounds, Rect destinationBounds) {
@@ -52,8 +51,7 @@
                 .setCornerRadius(leash, mCornerRadius);
         return new PictureInPictureSurfaceTransaction(
                 mTmpDestinationRectF.left, mTmpDestinationRectF.top,
-                mTmpFloat9[MSCALE_X], mTmpFloat9[MSCALE_Y],
-                0 /* rotation*/, mCornerRadius, sourceBounds);
+                mTmpFloat9, 0 /* rotation */, mCornerRadius, sourceBounds);
     }
 
     public PictureInPictureSurfaceTransaction scale(
@@ -68,9 +66,7 @@
                 .setPosition(leash, positionX, positionY)
                 .setCornerRadius(leash, mCornerRadius);
         return new PictureInPictureSurfaceTransaction(
-                positionX, positionY,
-                mTmpFloat9[MSCALE_X], mTmpFloat9[MSCALE_Y],
-                degree, mCornerRadius, sourceBounds);
+                positionX, positionY, mTmpFloat9, degree, mCornerRadius, sourceBounds);
     }
 
     public PictureInPictureSurfaceTransaction scaleAndCrop(
@@ -92,7 +88,7 @@
                 .setPosition(leash, left, top)
                 .setCornerRadius(leash, mCornerRadius);
         return new PictureInPictureSurfaceTransaction(
-                left, top, scale, scale, 0 /* rotation */, mCornerRadius, mTmpDestinationRect);
+                left, top, mTmpFloat9, 0 /* rotation */, mCornerRadius, mTmpDestinationRect);
     }
 
     public PictureInPictureSurfaceTransaction scaleAndRotate(
@@ -114,7 +110,7 @@
                 .setPosition(leash, positionX, positionY)
                 .setCornerRadius(leash, mCornerRadius);
         return new PictureInPictureSurfaceTransaction(
-                positionX, positionY, scale, scale, degree, mCornerRadius, mTmpDestinationRect);
+                positionX, positionY, mTmpFloat9, degree, mCornerRadius, mTmpDestinationRect);
     }
 
     /** @return {@link SurfaceControl.Transaction} instance with vsync-id */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 927bce0..2cf3ad2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -105,6 +105,8 @@
     public static final int SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY = 1 << 17;
     // The IME is showing
     public static final int SYSUI_STATE_IME_SHOWING = 1 << 18;
+    // The window magnification is overlapped with system gesture insets at the bottom.
+    public static final int SYSUI_STATE_MAGNIFICATION_OVERLAP = 1 << 19;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -125,7 +127,8 @@
             SYSUI_STATE_GLOBAL_ACTIONS_SHOWING,
             SYSUI_STATE_ONE_HANDED_ACTIVE,
             SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
-            SYSUI_STATE_IME_SHOWING
+            SYSUI_STATE_IME_SHOWING,
+            SYSUI_STATE_MAGNIFICATION_OVERLAP
     })
     public @interface SystemUiStateFlags {}
 
@@ -153,6 +156,7 @@
         str.add((flags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0
                 ? "allow_gesture" : "");
         str.add((flags & SYSUI_STATE_IME_SHOWING) != 0 ? "ime_visible" : "");
+        str.add((flags & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0 ? "magnification_overlap" : "");
         return str.toString();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 76cec0b..64a683e 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -305,10 +305,15 @@
                     continue;
                 }
                 Rect subImage = new Rect(
-                        Math.round(area.left * b.getWidth()),
-                        Math.round(area.top * b.getHeight()),
-                        Math.round(area.right * b.getWidth()),
-                        Math.round(area.bottom * b.getHeight()));
+                        (int) Math.floor(area.left * b.getWidth()),
+                        (int) Math.floor(area.top * b.getHeight()),
+                        (int) Math.ceil(area.right * b.getWidth()),
+                        (int) Math.ceil(area.bottom * b.getHeight()));
+                if (subImage.isEmpty()) {
+                    // Do not notify client. treat it as too small to sample
+                    colors.add(null);
+                    continue;
+                }
                 Bitmap colorImg = Bitmap.createBitmap(b,
                         subImage.left, subImage.top, subImage.width(), subImage.height());
                 WallpaperColors color = WallpaperColors.fromBitmap(colorImg);
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 7f18379..bf09975 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -73,7 +73,8 @@
             Key.TOUCHED_RINGER_TOGGLE,
             Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP,
             Key.HAS_SEEN_REVERSE_BOTTOM_SHEET,
-            Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
+            Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT,
+            Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP
     })
     // TODO: annotate these with their types so {@link PrefsCommandLine} can know how to set them
     public @interface Key {
@@ -122,6 +123,8 @@
         String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip";
         String HAS_SEEN_REVERSE_BOTTOM_SHEET = "HasSeenReverseBottomSheet";
         String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
+        String HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP =
+                "HasSeenAccessibilityFloatingMenuDockTooltip";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java b/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java
index b69001d..c472457 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java
@@ -63,17 +63,15 @@
     }
 
     /**
-     * Gets the object by the element index.
+     * Returns the object with the given display id.
      *
-     * <p> If the index is bigger than the array size, an {@link ArrayIndexOutOfBoundsException} is
-     * thrown for apps targeting {@link android.os.Build.VERSION_CODES#Q} and later </p>
      *
-     * @param index the element index
+     * @param displayId the logical display Id
      * @return T
-     * @see SparseArray#valueAt(int)
      */
-    public T valueAt(int index) {
-        return mSparseArray.valueAt(index);
+    @Nullable
+    public T valueAt(int displayId) {
+        return mSparseArray.get(displayId);
     }
 
     @NonNull
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationGestureDetector.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationGestureDetector.java
index 4c892e29..4b30ec3 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationGestureDetector.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationGestureDetector.java
@@ -113,7 +113,7 @@
         final float rawX = event.getRawX();
         final float rawY = event.getRawY();
         boolean handled = false;
-        switch (event.getAction()) {
+        switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
                 mPointerDown.set(rawX, rawY);
                 mHandler.postAtTime(mCancelTapGestureRunnable,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 4f5fdc9..cee395b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -18,10 +18,11 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
 
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
+
 import android.annotation.MainThread;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
@@ -37,9 +38,13 @@
 import com.android.systemui.SystemUI;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.statusbar.CommandQueue;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 import javax.inject.Inject;
 
 /**
@@ -52,34 +57,33 @@
 public class WindowMagnification extends SystemUI implements WindowMagnifierCallback,
         CommandQueue.Callbacks {
     private static final String TAG = "WindowMagnification";
-    private static final int CONFIG_MASK =
-            ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION
-                    | ActivityInfo.CONFIG_LOCALE;
 
     private final ModeSwitchesController mModeSwitchesController;
     private final Handler mHandler;
     private final AccessibilityManager mAccessibilityManager;
     private final CommandQueue mCommandQueue;
+    private final OverviewProxyService mOverviewProxyService;
 
     private WindowMagnificationConnectionImpl mWindowMagnificationConnectionImpl;
     private Configuration mLastConfiguration;
+    private SysUiState mSysUiState;
 
     private static class AnimationControllerSupplier extends
             DisplayIdIndexSupplier<WindowMagnificationAnimationController> {
 
         private final Context mContext;
         private final Handler mHandler;
-        private final NavigationModeController mNavigationModeController;
         private final WindowMagnifierCallback mWindowMagnifierCallback;
+        private final SysUiState mSysUiState;
 
         AnimationControllerSupplier(Context context, Handler handler,
-                NavigationModeController navigationModeController,
-                WindowMagnifierCallback windowMagnifierCallback, DisplayManager displayManager) {
+                WindowMagnifierCallback windowMagnifierCallback,
+                DisplayManager displayManager, SysUiState sysUiState) {
             super(displayManager);
             mContext = context;
             mHandler = handler;
-            mNavigationModeController = navigationModeController;
             mWindowMagnifierCallback = windowMagnifierCallback;
+            mSysUiState = sysUiState;
         }
 
         @Override
@@ -89,10 +93,7 @@
             final WindowMagnificationController controller = new WindowMagnificationController(
                     mContext,
                     mHandler, new SfVsyncFrameCallbackProvider(), null,
-                    new SurfaceControl.Transaction(), mWindowMagnifierCallback);
-            final int navBarMode = mNavigationModeController.addListener(
-                    controller::onNavigationModeChanged);
-            controller.onNavigationModeChanged(navBarMode);
+                    new SurfaceControl.Transaction(), mWindowMagnifierCallback, mSysUiState);
             return new WindowMagnificationAnimationController(windowContext, controller);
         }
     }
@@ -103,24 +104,22 @@
     @Inject
     public WindowMagnification(Context context, @Main Handler mainHandler,
             CommandQueue commandQueue, ModeSwitchesController modeSwitchesController,
-            NavigationModeController navigationModeController) {
+            SysUiState sysUiState, OverviewProxyService overviewProxyService) {
         super(context);
         mHandler = mainHandler;
         mLastConfiguration = new Configuration(context.getResources().getConfiguration());
         mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
         mCommandQueue = commandQueue;
         mModeSwitchesController = modeSwitchesController;
+        mSysUiState = sysUiState;
+        mOverviewProxyService = overviewProxyService;
         mAnimationControllerSupplier = new AnimationControllerSupplier(context,
-                mHandler, navigationModeController, this,
-                context.getSystemService(DisplayManager.class));
+                mHandler, this, context.getSystemService(DisplayManager.class), sysUiState);
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         final int configDiff = newConfig.diff(mLastConfiguration);
-        if ((configDiff & CONFIG_MASK) == 0) {
-            return;
-        }
         mLastConfiguration.setTo(newConfig);
         mAnimationControllerSupplier.forEach(
                 animationController -> animationController.onConfigurationChanged(configDiff));
@@ -132,6 +131,28 @@
     @Override
     public void start() {
         mCommandQueue.addCallback(this);
+        mOverviewProxyService.addCallback(new OverviewProxyService.OverviewProxyListener() {
+            @Override
+            public void onConnectionChanged(boolean isConnected) {
+                if (isConnected) {
+                    updateSysUiStateFlag();
+                }
+            }
+        });
+    }
+
+    private void updateSysUiStateFlag() {
+        //TODO(b/187510533): support multi-display once SysuiState supports it.
+        final WindowMagnificationAnimationController controller =
+                mAnimationControllerSupplier.valueAt(Display.DEFAULT_DISPLAY);
+        if (controller != null) {
+            controller.updateSysUiStateFlag();
+        } else {
+            // The instance is initialized when there is an IPC request. Considering
+            // self-crash cases, we need to reset the flag in such situation.
+            mSysUiState.setFlag(SYSUI_STATE_MAGNIFICATION_OVERLAP, false)
+                    .commitUpdate(Display.DEFAULT_DISPLAY);
+        }
     }
 
     @MainThread
@@ -210,6 +231,13 @@
         }
     }
 
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println(TAG);
+        mAnimationControllerSupplier.forEach(
+                animationController -> animationController.dump(pw));
+    }
+
     private void setWindowMagnificationConnection() {
         if (mWindowMagnificationConnectionImpl == null) {
             mWindowMagnificationConnectionImpl = new WindowMagnificationConnectionImpl(this,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
index 5758b15..36fef3e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java
@@ -31,6 +31,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -269,6 +270,14 @@
         mController.enableWindowMagnification(sentScale, centerX, centerY);
     }
 
+    public void updateSysUiStateFlag() {
+        mController.updateSysUIStateFlag();
+    }
+
+    void dump(PrintWriter pw) {
+        mController.dump(pw);
+    }
+
     private static ValueAnimator newValueAnimator(Resources resources) {
         final ValueAnimator valueAnimator = new ValueAnimator();
         valueAnimator.setDuration(
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index ae16703..fcb090a 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -16,9 +16,10 @@
 
 package com.android.systemui.accessibility;
 
+import static android.view.WindowInsets.Type.systemGestures;
 import static android.view.WindowManager.LayoutParams;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
 
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
@@ -28,6 +29,7 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
+import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -52,14 +54,17 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
+import android.view.WindowMetrics;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.systemui.R;
+import com.android.systemui.model.SysUiState;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
+import java.io.PrintWriter;
 import java.text.NumberFormat;
 import java.util.Locale;
 
@@ -111,6 +116,7 @@
     private final View.OnLayoutChangeListener mMirrorSurfaceViewLayoutChangeListener;
     private final Runnable mMirrorViewRunnable;
     private final Runnable mUpdateStateDescriptionRunnable;
+    private final Runnable mWindowInsetChangeRunnable;
     private View mMirrorView;
     private SurfaceView mMirrorSurfaceView;
     private int mMirrorSurfaceMargin;
@@ -119,9 +125,8 @@
     private int mOuterBorderSize;
     // The boundary of magnification frame.
     private final Rect mMagnificationFrameBoundary = new Rect();
-
-    private int mNavBarMode;
-    private int mNavGestureHeight;
+    // The top Y of the system gesture rect at the bottom. Set to -1 if it is invalid.
+    private int mSystemGestureTop = -1;
 
     private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
     private final MagnificationGestureDetector mGestureDetector;
@@ -130,6 +135,9 @@
     private Locale mLocale;
     private NumberFormat mPercentFormat;
     private float mBounceEffectAnimationScale;
+    private SysUiState mSysUiState;
+    // Set it to true when the view is overlapped with the gesture insets at the bottom.
+    private boolean mOverlapWithGestureInsets;
 
     @Nullable
     private MirrorWindowControl mMirrorWindowControl;
@@ -137,11 +145,12 @@
     WindowMagnificationController(@UiContext Context context, @NonNull Handler handler,
             SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
             MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
-            @NonNull WindowMagnifierCallback callback) {
+            @NonNull WindowMagnifierCallback callback, SysUiState sysUiState) {
         mContext = context;
         mHandler = handler;
         mSfVsyncFrameProvider = sfVsyncFrameProvider;
         mWindowMagnifierCallback = callback;
+        mSysUiState = sysUiState;
 
         final Display display = mContext.getDisplay();
         mDisplayId = mContext.getDisplayId();
@@ -170,13 +179,18 @@
         mMirrorViewRunnable = () -> {
             if (mMirrorView != null) {
                 mMirrorView.getBoundsOnScreen(mMirrorViewBounds);
+                updateSystemUIStateIfNeeded();
                 mWindowMagnifierCallback.onWindowMagnifierBoundsChanged(
                         mDisplayId, mMirrorViewBounds);
             }
         };
         mMirrorViewLayoutChangeListener =
-                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    if (!mHandler.hasCallbacks(mMirrorViewRunnable)) {
                         mHandler.post(mMirrorViewRunnable);
+                    }
+                };
+
         mMirrorSurfaceViewLayoutChangeListener =
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
                         -> applyTapExcludeRegion();
@@ -199,6 +213,7 @@
                 mMirrorView.setStateDescription(formatStateDescription(mScale));
             }
         };
+        mWindowInsetChangeRunnable = this::onWindowInsetChanged;
     }
 
     private void updateDimensions() {
@@ -210,7 +225,6 @@
                 R.dimen.magnification_drag_view_size);
         mOuterBorderSize = mResources.getDimensionPixelSize(
                 R.dimen.magnification_outer_border_margin);
-        updateNavigationBarDimensions();
     }
 
     private void computeBounceAnimationScale() {
@@ -220,16 +234,16 @@
         mBounceEffectAnimationScale = Math.min(animationScaleMax, ANIMATION_BOUNCE_EFFECT_SCALE);
     }
 
-    private void updateNavigationBarDimensions() {
-        if (!supportsSwipeUpGesture()) {
-            mNavGestureHeight = 0;
-            return;
+    private boolean updateSystemGestureInsetsTop() {
+        final WindowMetrics windowMetrics = mWm.getCurrentWindowMetrics();
+        final Insets insets = windowMetrics.getWindowInsets().getInsets(systemGestures());
+        final int gestureTop =
+                insets.bottom != 0 ? windowMetrics.getBounds().bottom - insets.bottom : -1;
+        if (gestureTop != mSystemGestureTop) {
+            mSystemGestureTop = gestureTop;
+            return true;
         }
-        mNavGestureHeight = (mWindowBounds.width() > mWindowBounds.height())
-                ? mResources.getDimensionPixelSize(
-                com.android.internal.R.dimen.navigation_bar_height_landscape)
-                : mResources.getDimensionPixelSize(
-                        com.android.internal.R.dimen.navigation_bar_gesture_height);
+        return false;
     }
 
     /**
@@ -255,6 +269,7 @@
         if (mMirrorWindowControl != null) {
             mMirrorWindowControl.destroyControl();
         }
+        updateSystemUIStateIfNeeded();
     }
 
     /**
@@ -277,6 +292,10 @@
         }
     }
 
+    private void updateSystemUIStateIfNeeded() {
+        updateSysUIState(false);
+    }
+
     private void updateAccessibilityWindowTitleIfNeeded() {
         if (!isWindowVisible()) return;
         LayoutParams params = (LayoutParams) mMirrorView.getLayoutParams();
@@ -284,13 +303,6 @@
         mWm.updateViewLayout(mMirrorView, params);
     }
 
-    /** Handles MirrorWindow position when the navigation bar mode changed. */
-    public void onNavigationModeChanged(int mode) {
-        mNavBarMode = mode;
-        updateNavigationBarDimensions();
-        updateMirrorViewLayout();
-    }
-
     /** Handles MirrorWindow position when the device rotation changed. */
     private void onRotate() {
         final Display display = mContext.getDisplay();
@@ -299,7 +311,6 @@
 
         setMagnificationFrameBoundary();
         mRotation = display.getRotation();
-        updateNavigationBarDimensions();
 
         if (!isWindowVisible()) {
             return;
@@ -351,6 +362,7 @@
         params.x = mMagnificationFrame.left - mMirrorSurfaceMargin;
         params.y = mMagnificationFrame.top - mMirrorSurfaceMargin;
         params.layoutInDisplayCutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+        params.receiveInsetsIgnoringZOrder = true;
         params.setTitle(mContext.getString(R.string.magnification_window_title));
         params.accessibilityTitle = getAccessibilityWindowTitle();
 
@@ -368,6 +380,12 @@
                 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
         mMirrorView.addOnLayoutChangeListener(mMirrorViewLayoutChangeListener);
         mMirrorView.setAccessibilityDelegate(new MirrorWindowA11yDelegate());
+        mMirrorView.setOnApplyWindowInsetsListener((v, insets) -> {
+            if (!mHandler.hasCallbacks(mWindowInsetChangeRunnable)) {
+                mHandler.post(mWindowInsetChangeRunnable);
+            }
+            return v.onApplyWindowInsets(insets);
+        });
 
         mWm.addView(mMirrorView, params);
 
@@ -377,6 +395,12 @@
         addDragTouchListeners();
     }
 
+    private void onWindowInsetChanged() {
+        if (updateSystemGestureInsetsTop()) {
+            updateSystemUIStateIfNeeded();
+        }
+    }
+
     private void applyTapExcludeRegion() {
         final Region tapExcludeRegion = calculateTapExclude();
         final IWindow window = IWindow.Stub.asInterface(mMirrorView.getWindowToken());
@@ -464,17 +488,12 @@
             return;
         }
         final int maxMirrorViewX = mWindowBounds.width() - mMirrorView.getWidth();
-        final int maxMirrorViewY =
-                mWindowBounds.height() - mMirrorView.getHeight() - mNavGestureHeight;
+        final int maxMirrorViewY = mWindowBounds.height() - mMirrorView.getHeight();
+
         LayoutParams params =
                 (LayoutParams) mMirrorView.getLayoutParams();
         params.x = mMagnificationFrame.left - mMirrorSurfaceMargin;
         params.y = mMagnificationFrame.top - mMirrorSurfaceMargin;
-        // If nav bar mode supports swipe-up gesture, the Y position of mirror view should not
-        // overlap nav bar window to prevent window-dragging obscured.
-        if (supportsSwipeUpGesture()) {
-            params.y = Math.min(params.y, maxMirrorViewY);
-        }
 
         // Translates MirrorView position to make MirrorSurfaceView that is inside MirrorView
         // able to move close to the screen edges.
@@ -508,6 +527,10 @@
         return false;
     }
 
+    public void updateSysUIStateFlag() {
+        updateSysUIState(true);
+    }
+
     /**
      * Calculates the desired source bounds. This will be the area under from the center of  the
      * displayFrame, factoring in scale.
@@ -569,6 +592,16 @@
         return false;
     }
 
+    private void updateSysUIState(boolean force) {
+        final boolean overlap = isWindowVisible() && mSystemGestureTop > 0
+                && mMirrorViewBounds.bottom > mSystemGestureTop;
+        if (force || overlap != mOverlapWithGestureInsets) {
+            mOverlapWithGestureInsets = overlap;
+            mSysUiState.setFlag(SYSUI_STATE_MAGNIFICATION_OVERLAP, mOverlapWithGestureInsets)
+                    .commitUpdate(mDisplayId);
+        }
+    }
+
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
         createMirror();
@@ -676,10 +709,6 @@
         return mMirrorView != null;
     }
 
-    private boolean supportsSwipeUpGesture() {
-        return mNavBarMode == NAV_BAR_MODE_2BUTTON || mNavBarMode == NAV_BAR_MODE_GESTURAL;
-    }
-
     private CharSequence formatStateDescription(float scale) {
         // Cache the locale-appropriate NumberFormat.  Configuration locale is guaranteed
         // non-null, so the first time this is called we will always get the appropriate
@@ -722,6 +751,14 @@
         scaleAnimator.start();
     }
 
+    public void dump(PrintWriter pw) {
+        pw.println("WindowMagnificationController (displayId=" + mDisplayId + "):");
+        pw.println("      mOverlapWithGestureInsets:" + mOverlapWithGestureInsets);
+        pw.println("      mScale:" + mScale);
+        pw.println("      mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty"));
+        pw.println("      mSystemGestureTop:" + mSystemGestureTop);
+    }
+
     private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate {
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
index 3b3bad3..ee62768 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
@@ -18,11 +18,13 @@
 
 import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED;
 import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE;
+import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT;
 import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY;
 import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE;
 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
 
 import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
+import static com.android.systemui.Prefs.Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP;
 import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.ShapeType;
 import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.SizeType;
 
@@ -34,15 +36,19 @@
 import android.provider.Settings;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Prefs;
 
 /**
  * Contains logic for an accessibility floating menu view.
  */
 public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu {
-    private static final int DEFAULT_FADE_EFFECT_ENABLED = 1;
+    private static final int DEFAULT_FADE_EFFECT_IS_ENABLED = 1;
+    private static final int DEFAULT_MIGRATION_TOOLTIP_PROMPT_IS_DISABLED = 0;
     private static final float DEFAULT_OPACITY_VALUE = 0.55f;
     private final Context mContext;
     private final AccessibilityFloatingMenuView mMenuView;
+    private final MigrationTooltipView mMigrationTooltipView;
+    private final DockTooltipView mDockTooltipView;
     private final Handler mHandler = new Handler(Looper.getMainLooper());
 
     private final ContentObserver mContentObserver =
@@ -86,6 +92,8 @@
     AccessibilityFloatingMenu(Context context, AccessibilityFloatingMenuView menuView) {
         mContext = context;
         mMenuView = menuView;
+        mMigrationTooltipView = new MigrationTooltipView(mContext, mMenuView);
+        mDockTooltipView = new DockTooltipView(mContext, mMenuView);
     }
 
     @Override
@@ -105,6 +113,9 @@
                 getOpacityValue(mContext));
         mMenuView.setSizeType(getSizeType(mContext));
         mMenuView.setShapeType(getShapeType(mContext));
+        mMenuView.setOnDragEndListener(this::showDockTooltipIfNecessary);
+
+        showMigrationTooltipIfNecessary();
 
         registerContentObservers();
     }
@@ -116,14 +127,48 @@
         }
 
         mMenuView.hide();
+        mMigrationTooltipView.hide();
+        mDockTooltipView.hide();
 
         unregisterContentObservers();
     }
 
+    // Migration tooltip was the android S feature. It's just used on the Android version from R
+    // to S. In addition, it only shows once.
+    private void showMigrationTooltipIfNecessary() {
+        if (isMigrationTooltipPromptEnabled(mContext)) {
+            mMigrationTooltipView.show();
+
+            Settings.Secure.putInt(mContext.getContentResolver(),
+                    ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT, /* disabled */ 0);
+        }
+    }
+
+    private static boolean isMigrationTooltipPromptEnabled(Context context) {
+        return Settings.Secure.getInt(
+                context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
+                DEFAULT_MIGRATION_TOOLTIP_PROMPT_IS_DISABLED) == /* enabled */ 1;
+    }
+
+    /**
+     * Shows tooltip when user drags accessibility floating menu for the first time.
+     */
+    private void showDockTooltipIfNecessary() {
+        if (!Prefs.get(mContext).getBoolean(
+                HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP, false)) {
+            // if the menu is an oval, the user has already dragged it out, so show the tooltip.
+            if (mMenuView.isOvalShape()) {
+                mDockTooltipView.show();
+            }
+
+            Prefs.putBoolean(mContext, HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP, true);
+        }
+    }
+
     private static boolean isFadeEffectEnabled(Context context) {
         return Settings.Secure.getInt(
                 context.getContentResolver(), ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
-                DEFAULT_FADE_EFFECT_ENABLED) == /* enable */ 1;
+                DEFAULT_FADE_EFFECT_IS_ENABLED) == /* enabled */ 1;
     }
 
     private static float getOpacityValue(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
index 934e20d..49e6b47 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -19,6 +19,8 @@
 import static android.util.MathUtils.constrain;
 import static android.util.MathUtils.sq;
 
+import static java.util.Objects.requireNonNull;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -43,7 +45,9 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.view.animation.Animation;
 import android.view.animation.OvershootInterpolator;
+import android.view.animation.TranslateAnimation;
 import android.widget.FrameLayout;
 
 import androidx.annotation.DimenRes;
@@ -60,6 +64,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * Accessibility floating menu is used for the actions of accessibility features, it's also the
@@ -78,6 +83,10 @@
     private static final int MIN_WINDOW_Y = 0;
     private static final float LOCATION_Y_PERCENTAGE = 0.8f;
 
+    private static final int ANIMATION_START_OFFSET = 600;
+    private static final int ANIMATION_DURATION_MS = 600;
+    private static final float ANIMATION_TO_X_VALUE = 0.5f;
+
     private boolean mIsFadeEffectEnabled;
     private boolean mIsShowing;
     private boolean mIsDownInEnlargedTouchArea;
@@ -107,6 +116,7 @@
     private float mPercentageY = LOCATION_Y_PERCENTAGE;
     private float mSquareScaledTouchSlop;
     private final Configuration mLastConfiguration;
+    private Optional<OnDragEndListener> mOnDragEndListener = Optional.empty();
     private final RecyclerView mListView;
     private final AccessibilityTargetAdapter mAdapter;
     private float mFadeOutValue;
@@ -161,6 +171,17 @@
         int RIGHT = 1;
     }
 
+    /**
+     * Interface for a callback to be invoked when the floating menu was dragging.
+     */
+    interface OnDragEndListener {
+
+        /**
+         * Invoked when the floating menu has dragged end.
+         */
+        void onDragEnd();
+    }
+
     public AccessibilityFloatingMenuView(Context context) {
         this(context, new RecyclerView(context));
     }
@@ -201,6 +222,8 @@
                 updateRadiusWith(mSizeType, mRadiusType, mTargets.size());
 
                 fadeOut();
+
+                mOnDragEndListener.ifPresent(OnDragEndListener::onDragEnd);
             }
         });
 
@@ -266,7 +289,7 @@
 
                 // Must switch the oval shape type before tapping the corresponding item in the
                 // list view, otherwise it can't work on it.
-                if (mShapeType == ShapeType.HALF_OVAL) {
+                if (!isOvalShape()) {
                     setShapeType(ShapeType.OVAL);
 
                     return true;
@@ -299,10 +322,6 @@
 
     @Override
     public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
-            return true;
-        }
-
         fadeIn();
 
         final Rect bounds = getAvailableBounds();
@@ -340,7 +359,7 @@
             return true;
         }
 
-        return false;
+        return super.performAccessibilityAction(action, arguments);
     }
 
     void show() {
@@ -367,6 +386,10 @@
         return mIsShowing;
     }
 
+    boolean isOvalShape() {
+        return mShapeType == ShapeType.OVAL;
+    }
+
     void onTargetsChanged(List<AccessibilityTarget> newTargets) {
         fadeIn();
 
@@ -411,6 +434,41 @@
         fadeOut();
     }
 
+    public void setOnDragEndListener(OnDragEndListener onDragListener) {
+        mOnDragEndListener = Optional.ofNullable(onDragListener);
+    }
+
+    void startTranslateXAnimation() {
+        fadeIn();
+
+        final float toXValue = mAlignment == Alignment.RIGHT
+                ? ANIMATION_TO_X_VALUE
+                : -ANIMATION_TO_X_VALUE;
+        final TranslateAnimation animation =
+                new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
+                        Animation.RELATIVE_TO_SELF, toXValue,
+                        Animation.RELATIVE_TO_SELF, 0,
+                        Animation.RELATIVE_TO_SELF, 0);
+        animation.setDuration(ANIMATION_DURATION_MS);
+        animation.setRepeatMode(Animation.REVERSE);
+        animation.setInterpolator(new OvershootInterpolator());
+        animation.setRepeatCount(Animation.INFINITE);
+        animation.setStartOffset(ANIMATION_START_OFFSET);
+        mListView.startAnimation(animation);
+    }
+
+    void stopTranslateXAnimation() {
+        mListView.clearAnimation();
+
+        fadeOut();
+    }
+
+    Rect getWindowLocationOnScreen() {
+        final int left = mCurrentLayoutParams.x;
+        final int top = mCurrentLayoutParams.y;
+        return new Rect(left, top, left + getWindowWidth(), top + getWindowHeight());
+    }
+
     void updateOpacityWith(boolean isFadeEffectEnabled, float newOpacityValue) {
         mIsFadeEffectEnabled = isFadeEffectEnabled;
         mFadeOutValue = newOpacityValue;
@@ -534,11 +592,7 @@
     }
 
     private Handler createUiHandler() {
-        final Looper looper = Looper.myLooper();
-        if (looper == null) {
-            throw new IllegalArgumentException("looper must not be null");
-        }
-        return new Handler(looper);
+        return new Handler(requireNonNull(Looper.myLooper(), "looper must not be null"));
     }
 
     private void updateDimensions() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java
new file mode 100644
index 0000000..d8e80fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import android.text.Annotation;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.style.ClickableSpan;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+/**
+ * A span that turns the text wrapped by annotation tag into the clickable link text.
+ */
+class AnnotationLinkSpan extends ClickableSpan {
+    private final Optional<View.OnClickListener> mClickListener;
+
+    private AnnotationLinkSpan(View.OnClickListener listener) {
+        mClickListener = Optional.ofNullable(listener);
+    }
+
+    @Override
+    public void onClick(View view) {
+        mClickListener.ifPresent(listener -> listener.onClick(view));
+    }
+
+    /**
+     * Makes the text has the link with the click action. In addition, the span will match first
+     * LinkInfo and attach into the text.
+     *
+     * @param text the text wrapped by annotation tag
+     * @param linkInfos used to attach the click action into the corresponding span
+     * @return the text attached with the span
+     */
+    static CharSequence linkify(CharSequence text, LinkInfo... linkInfos) {
+        final SpannableString msg = new SpannableString(text);
+        final Annotation[] spans =
+                msg.getSpans(/* queryStart= */ 0, msg.length(), Annotation.class);
+        final SpannableStringBuilder builder = new SpannableStringBuilder(msg);
+
+        Arrays.asList(spans).forEach(annotationTag -> {
+            final String key = annotationTag.getValue();
+            final Optional<LinkInfo> linkInfo =
+                    Arrays.asList(linkInfos).stream().filter(
+                            info -> info.mAnnotation.isPresent()
+                                    && info.mAnnotation.get().equals(key)).findFirst();
+
+            linkInfo.flatMap(info -> info.mListener).ifPresent(listener -> {
+                final AnnotationLinkSpan span = new AnnotationLinkSpan(listener);
+                builder.setSpan(span,
+                        msg.getSpanStart(annotationTag),
+                        msg.getSpanEnd(annotationTag),
+                        msg.getSpanFlags(span));
+            });
+        });
+
+        return builder;
+    }
+
+    /**
+     * Data class to store the annotation and the click action.
+     */
+    static class LinkInfo {
+        static final String DEFAULT_ANNOTATION = "link";
+        private final Optional<String> mAnnotation;
+        private final Optional<View.OnClickListener> mListener;
+
+        LinkInfo(@NonNull String annotation, View.OnClickListener listener) {
+            mAnnotation = Optional.of(annotation);
+            mListener = Optional.ofNullable(listener);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java
new file mode 100644
index 0000000..1abf559
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static android.util.TypedValue.COMPLEX_UNIT_PX;
+import static android.view.View.MeasureSpec.AT_MOST;
+import static android.view.View.MeasureSpec.UNSPECIFIED;
+
+import android.annotation.UiContext;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.CornerPathEffect;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.os.Bundle;
+import android.text.method.MovementMethod;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+import com.android.systemui.recents.TriangleShape;
+
+/**
+ * Base tooltip view that shows the information about the operation of the
+ * Accessibility floating menu. In addition, the anchor view is only for {@link
+ * AccessibilityFloatingMenuView}, it should be more suited for displaying one-off menus to avoid
+ * the performance hit for the extra window.
+ */
+class BaseTooltipView extends FrameLayout {
+    private int mFontSize;
+    private int mTextViewMargin;
+    private int mTextViewPadding;
+    private int mTextViewCornerRadius;
+    private int mArrowMargin;
+    private int mArrowWidth;
+    private int mArrowHeight;
+    private int mArrowCornerRadius;
+    private int mScreenWidth;
+    private boolean mIsShowing;
+    private TextView mTextView;
+    private final WindowManager.LayoutParams mCurrentLayoutParams;
+    private final WindowManager mWindowManager;
+    private final AccessibilityFloatingMenuView mAnchorView;
+
+    BaseTooltipView(@UiContext Context context, AccessibilityFloatingMenuView anchorView) {
+        super(context);
+        mWindowManager = context.getSystemService(WindowManager.class);
+        mAnchorView = anchorView;
+        mCurrentLayoutParams = createDefaultLayoutParams();
+
+        updateDimensions();
+        initViews();
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        updateDimensions();
+        updateTextView();
+
+        mAnchorView.onConfigurationChanged(newConfig);
+        final Rect anchorViewLocation = mAnchorView.getWindowLocationOnScreen();
+        updateArrowWith(anchorViewLocation);
+        updateWidthWith(anchorViewLocation);
+        updateLocationWith(anchorViewLocation);
+
+        mWindowManager.updateViewLayout(this, mCurrentLayoutParams);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+            hide();
+        }
+
+        return super.onTouchEvent(event);
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+
+        info.addAction(AccessibilityAction.ACTION_DISMISS);
+    }
+
+    @Override
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        if (action == AccessibilityAction.ACTION_DISMISS.getId()) {
+            hide();
+            return true;
+        }
+
+        return super.performAccessibilityAction(action, arguments);
+    }
+
+    void show() {
+        if (isShowing()) {
+            return;
+        }
+
+        mIsShowing = true;
+        final Rect anchorViewLocation = mAnchorView.getWindowLocationOnScreen();
+        updateArrowWith(anchorViewLocation);
+        updateWidthWith(anchorViewLocation);
+        updateLocationWith(anchorViewLocation);
+
+        mWindowManager.addView(this, mCurrentLayoutParams);
+    }
+
+    void hide() {
+        if (!isShowing()) {
+            return;
+        }
+
+        mIsShowing = false;
+        mWindowManager.removeView(this);
+    }
+
+    void setDescription(CharSequence text) {
+        mTextView.setText(text);
+    }
+
+    void setMovementMethod(MovementMethod movement) {
+        mTextView.setMovementMethod(movement);
+    }
+
+    private boolean isShowing() {
+        return mIsShowing;
+    }
+
+    private void initViews() {
+        final View contentView =
+                LayoutInflater.from(getContext()).inflate(
+                        R.layout.accessibility_floating_menu_tooltip, this, false);
+
+        mTextView = contentView.findViewById(R.id.text);
+
+        addView(contentView);
+    }
+
+    private static WindowManager.LayoutParams createDefaultLayoutParams() {
+        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
+                PixelFormat.TRANSLUCENT);
+        params.windowAnimations = android.R.style.Animation_Translucent;
+        params.gravity = Gravity.START | Gravity.TOP;
+
+        return params;
+    }
+
+    private void updateDimensions() {
+        final Resources res = getResources();
+        final DisplayMetrics dm = res.getDisplayMetrics();
+        mScreenWidth = dm.widthPixels;
+        mArrowWidth =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_arrow_width);
+        mArrowHeight =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_arrow_height);
+        mArrowMargin =
+                res.getDimensionPixelSize(
+                        R.dimen.accessibility_floating_tooltip_arrow_margin);
+        mArrowCornerRadius =
+                res.getDimensionPixelSize(
+                        R.dimen.accessibility_floating_tooltip_arrow_corner_radius);
+        mFontSize =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_font_size);
+        mTextViewMargin =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_margin);
+        mTextViewPadding =
+                res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_padding);
+        mTextViewCornerRadius =
+                res.getDimensionPixelSize(
+                        R.dimen.accessibility_floating_tooltip_text_corner_radius);
+    }
+
+    private void updateTextView() {
+        mTextView.setTextSize(COMPLEX_UNIT_PX, mFontSize);
+        mTextView.setPadding(mTextViewPadding, mTextViewPadding, mTextViewPadding,
+                mTextViewPadding);
+
+        final GradientDrawable gradientDrawable = (GradientDrawable) mTextView.getBackground();
+        gradientDrawable.setCornerRadius(mTextViewCornerRadius);
+    }
+
+    private void updateArrowWith(Rect anchorViewLocation) {
+        final boolean isAnchorViewOnLeft = isAnchorViewOnLeft(anchorViewLocation);
+        final View arrowView = findViewById(isAnchorViewOnLeft
+                ? R.id.arrow_left
+                : R.id.arrow_right);
+        arrowView.setVisibility(VISIBLE);
+        drawArrow(arrowView, isAnchorViewOnLeft);
+
+        final LinearLayout.LayoutParams layoutParams =
+                (LinearLayout.LayoutParams) arrowView.getLayoutParams();
+        layoutParams.width = mArrowWidth;
+        layoutParams.height = mArrowHeight;
+
+        final int leftMargin = isAnchorViewOnLeft ? 0 : mArrowMargin;
+        final int rightMargin = isAnchorViewOnLeft ? mArrowMargin : 0;
+        layoutParams.setMargins(leftMargin, 0, rightMargin, 0);
+        arrowView.setLayoutParams(layoutParams);
+    }
+
+    private void updateWidthWith(Rect anchorViewLocation) {
+        final ViewGroup.LayoutParams layoutParams = mTextView.getLayoutParams();
+        layoutParams.width = getTextWidthWith(anchorViewLocation);
+        mTextView.setLayoutParams(layoutParams);
+    }
+
+    private void updateLocationWith(Rect anchorViewLocation) {
+        mCurrentLayoutParams.x = isAnchorViewOnLeft(anchorViewLocation)
+                ? anchorViewLocation.width()
+                : mScreenWidth - getWindowWidthWith(anchorViewLocation)
+                        - anchorViewLocation.width();
+        mCurrentLayoutParams.y =
+                anchorViewLocation.centerY() - (getTextHeightWith(anchorViewLocation) / 2);
+    }
+
+    private void drawArrow(View view, boolean isPointingLeft) {
+        final ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
+        final TriangleShape triangleShape =
+                TriangleShape.createHorizontal(layoutParams.width, layoutParams.height,
+                        isPointingLeft);
+        final ShapeDrawable arrowDrawable = new ShapeDrawable(triangleShape);
+        final Paint arrowPaint = arrowDrawable.getPaint();
+        arrowPaint.setColor(Utils.getColorAttrDefaultColor(getContext(),
+                com.android.internal.R.attr.colorAccentPrimary));
+        final CornerPathEffect effect = new CornerPathEffect(mArrowCornerRadius);
+        arrowPaint.setPathEffect(effect);
+        view.setBackground(arrowDrawable);
+    }
+
+    private boolean isAnchorViewOnLeft(Rect anchorViewLocation) {
+        return anchorViewLocation.left < (mScreenWidth / 2);
+    }
+
+    private int getTextWidthWith(Rect anchorViewLocation) {
+        final int widthSpec =
+                MeasureSpec.makeMeasureSpec(getAvailableTextWidthWith(anchorViewLocation), AT_MOST);
+        final int heightSpec =
+                MeasureSpec.makeMeasureSpec(0, UNSPECIFIED);
+        mTextView.measure(widthSpec, heightSpec);
+        return mTextView.getMeasuredWidth();
+    }
+
+    private int getTextHeightWith(Rect anchorViewLocation) {
+        final int widthSpec =
+                MeasureSpec.makeMeasureSpec(getAvailableTextWidthWith(anchorViewLocation), AT_MOST);
+        final int heightSpec =
+                MeasureSpec.makeMeasureSpec(0, UNSPECIFIED);
+        mTextView.measure(widthSpec, heightSpec);
+        return mTextView.getMeasuredHeight();
+    }
+
+    private int getAvailableTextWidthWith(Rect anchorViewLocation) {
+        return mScreenWidth - anchorViewLocation.width() - mArrowWidth - mArrowMargin
+                - mTextViewMargin;
+    }
+
+    private int getWindowWidthWith(Rect anchorViewLocation) {
+        return getTextWidthWith(anchorViewLocation) + mArrowWidth + mArrowMargin;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DockTooltipView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DockTooltipView.java
new file mode 100644
index 0000000..49056a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DockTooltipView.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import android.content.Context;
+
+import com.android.systemui.R;
+
+/**
+ * Dock tooltip view that shows the info about moving the Accessibility button to the edge to hide.
+ */
+class DockTooltipView extends BaseTooltipView {
+    private final AccessibilityFloatingMenuView mAnchorView;
+
+    DockTooltipView(Context context, AccessibilityFloatingMenuView anchorView) {
+        super(context, anchorView);
+        mAnchorView = anchorView;
+
+        setDescription(
+                getContext().getText(R.string.accessibility_floating_button_docking_tooltip));
+    }
+
+    @Override
+    void hide() {
+        super.hide();
+
+        mAnchorView.stopTranslateXAnimation();
+    }
+
+    @Override
+    void show() {
+        super.show();
+
+        mAnchorView.startTranslateXAnimation();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipView.java
new file mode 100644
index 0000000..e4f3e31
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipView.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_BUTTON_COMPONENT_NAME;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.text.method.LinkMovementMethod;
+
+import com.android.systemui.R;
+
+/**
+ * Migration tooltip view that shows the information about the Accessibility button was replaced
+ * with the floating menu.
+ */
+class MigrationTooltipView extends BaseTooltipView {
+    MigrationTooltipView(Context context, AccessibilityFloatingMenuView anchorView) {
+        super(context, anchorView);
+
+        final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(Intent.EXTRA_COMPONENT_NAME,
+                ACCESSIBILITY_BUTTON_COMPONENT_NAME.flattenToShortString());
+
+        final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo(
+                AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION,
+                v -> {
+                    getContext().startActivity(intent);
+                    hide();
+                });
+
+        final int textResId = R.string.accessibility_floating_button_migration_tooltip;
+        setDescription(AnnotationLinkSpan.linkify(getContext().getText(textResId), linkInfo));
+        setMovementMethod(LinkMovementMethod.getInstance());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 5f27400..875bfdb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -59,7 +59,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
-import com.android.systemui.biometrics.HbmTypes.HbmType;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeReceiver;
@@ -72,6 +71,8 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
+import java.util.Optional;
+
 import javax.inject.Inject;
 
 /**
@@ -87,7 +88,7 @@
  */
 @SuppressWarnings("deprecation")
 @SysUISingleton
-public class UdfpsController implements DozeReceiver, HbmCallback {
+public class UdfpsController implements DozeReceiver {
     private static final String TAG = "UdfpsController";
     private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000;
 
@@ -105,11 +106,12 @@
     @NonNull private final DumpManager mDumpManager;
     @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @NonNull private final KeyguardViewMediator mKeyguardViewMediator;
-    @NonNull private final Vibrator mVibrator;
+    @Nullable private final Vibrator mVibrator;
     @NonNull private final Handler mMainHandler;
     @NonNull private final FalsingManager mFalsingManager;
     @NonNull private final PowerManager mPowerManager;
     @NonNull private final AccessibilityManager mAccessibilityManager;
+    @Nullable private final UdfpsHbmCallback mHbmCallback;
     // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
     // sensors, this, in addition to a lot of the code here, will be updated.
     @VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -135,7 +137,8 @@
     private boolean mScreenOn;
     private Runnable mAodInterruptRunnable;
 
-    private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
+    @VisibleForTesting
+    static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
             new AudioAttributes.Builder()
                     .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                     .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
@@ -144,7 +147,8 @@
     private final VibrationEffect mEffectTick = VibrationEffect.get(VibrationEffect.EFFECT_TICK);
     private final VibrationEffect mEffectTextureTick =
             VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK);
-    private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+    @VisibleForTesting
+    final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
     private final VibrationEffect mEffectHeavy =
             VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
     private final VibrationEffect mDoubleClick =
@@ -152,6 +156,9 @@
     private final Runnable mAcquiredVibration = new Runnable() {
         @Override
         public void run() {
+            if (mVibrator == null) {
+                return;
+            }
             String effect = Settings.Global.getString(mContext.getContentResolver(),
                     "udfps_acquired_type");
             mVibrator.vibrate(getVibration(effect, mEffectTick), VIBRATION_SONIFICATION_ATTRIBUTES);
@@ -389,24 +396,28 @@
                                     PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
 
                             // TODO: this should eventually be removed after ux testing
-                            final ContentResolver contentResolver = mContext.getContentResolver();
-                            int startEnabled = Settings.Global.getInt(contentResolver,
-                                    "udfps_start", 0);
-                            if (startEnabled > 0) {
-                                String startEffectSetting = Settings.Global.getString(
-                                        contentResolver, "udfps_start_type");
-                                mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick),
-                                        VIBRATION_SONIFICATION_ATTRIBUTES);
+                            if (mVibrator != null) {
+                                final ContentResolver contentResolver =
+                                        mContext.getContentResolver();
+                                int startEnabled = Settings.Global.getInt(contentResolver,
+                                        "udfps_start", 1);
+                                if (startEnabled > 0) {
+                                    String startEffectSetting = Settings.Global.getString(
+                                            contentResolver, "udfps_start_type");
+                                    mVibrator.vibrate(getVibration(startEffectSetting,
+                                            mEffectClick), VIBRATION_SONIFICATION_ATTRIBUTES);
+                                }
+
+                                int acquiredEnabled = Settings.Global.getInt(contentResolver,
+                                        "udfps_acquired", 0);
+                                if (acquiredEnabled > 0) {
+                                    int delay = Settings.Global.getInt(contentResolver,
+                                            "udfps_acquired_delay", 500);
+                                    mMainHandler.removeCallbacks(mAcquiredVibration);
+                                    mMainHandler.postDelayed(mAcquiredVibration, delay);
+                                }
                             }
 
-                            int acquiredEnabled = Settings.Global.getInt(contentResolver,
-                                    "udfps_acquired", 0);
-                            if (acquiredEnabled > 0) {
-                                int delay = Settings.Global.getInt(contentResolver,
-                                        "udfps_acquired_delay", 500);
-                                mMainHandler.removeCallbacks(mAcquiredVibration);
-                                mMainHandler.postDelayed(mAcquiredVibration, delay);
-                            }
                             handled = true;
                         } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
                             Log.v(TAG, "onTouch | finger move: " + touchInfo);
@@ -456,11 +467,13 @@
             @NonNull FalsingManager falsingManager,
             @NonNull PowerManager powerManager,
             @NonNull AccessibilityManager accessibilityManager,
-            @NonNull ScreenLifecycle screenLifecycle) {
+            @NonNull ScreenLifecycle screenLifecycle,
+            @Nullable Vibrator vibrator,
+            @NonNull Optional<UdfpsHbmCallback> hbmCallback) {
         mContext = context;
         // TODO (b/185124905): inject main handler and vibrator once done prototyping
         mMainHandler = new Handler(Looper.getMainLooper());
-        mVibrator = context.getSystemService(Vibrator.class);
+        mVibrator = vibrator;
         mInflater = inflater;
         // The fingerprint manager is queried for UDFPS before this class is constructed, so the
         // fingerprint manager should never be null.
@@ -476,6 +489,7 @@
         mFalsingManager = falsingManager;
         mPowerManager = powerManager;
         mAccessibilityManager = accessibilityManager;
+        mHbmCallback = hbmCallback.orElse(null);
         screenLifecycle.addObserver(mScreenObserver);
         mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
 
@@ -609,7 +623,7 @@
                     Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason);
                     mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
                     mView.setSensorProperties(mSensorProps);
-                    mView.setHbmCallback(this);
+                    mView.setHbmCallback(mHbmCallback);
                     UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason);
                     animation.init();
                     mView.setAnimationViewController(animation);
@@ -781,17 +795,6 @@
         mView.stopIllumination();
     }
 
-    @Override
-    public void enableHbm(@HbmType int hbmType, @Nullable Surface surface) {
-        // Do nothing. This method can be implemented for devices that require the high-brightness
-        // mode for fingerprint illumination.
-    }
-
-    @Override
-    public void disableHbm(@HbmType int hbmType, @Nullable Surface surface) {
-        // Do nothing. This method can be implemented for devices that require the high-brightness
-        // mode for fingerprint illumination.
-    }
 
     private VibrationEffect getVibration(String effect, VibrationEffect defaultEffect) {
         if (TextUtils.isEmpty(effect)) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/HbmCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHbmCallback.java
similarity index 92%
rename from packages/SystemUI/src/com/android/systemui/biometrics/HbmCallback.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHbmCallback.java
index d90d0f8..85f0d27 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/HbmCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHbmCallback.java
@@ -19,18 +19,18 @@
 import android.annotation.Nullable;
 import android.view.Surface;
 
-import com.android.systemui.biometrics.HbmTypes.HbmType;
+import com.android.systemui.biometrics.UdfpsHbmTypes.HbmType;
 
 /**
  * Interface for controlling the high-brightness mode (HBM). UdfpsView can use this callback to
  * enable the HBM while showing the fingerprint illumination, and to disable the HBM after the
  * illumination is no longer necessary.
  */
-public interface HbmCallback {
+public interface UdfpsHbmCallback {
     /**
      * UdfpsView will call this to enable the HBM when the fingerprint illumination is needed.
      *
-     * @param hbmType The type of HBM that should be enabled. See {@link HbmTypes}.
+     * @param hbmType The type of HBM that should be enabled. See {@link UdfpsHbmTypes}.
      * @param surface The surface for which the HBM is requested, in case the HBM implementation
      *                needs to set special surface flags to enable the HBM. Can be null.
      */
@@ -39,7 +39,7 @@
     /**
      * UdfpsView will call this to disable the HBM when the illumination is not longer needed.
      *
-     * @param hbmType The type of HBM that should be disabled. See {@link HbmTypes}.
+     * @param hbmType The type of HBM that should be disabled. See {@link UdfpsHbmTypes}.
      * @param surface The surface for which the HBM is requested, in case the HBM implementation
      *                needs to unset special surface flags to disable the HBM. Can be null.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/HbmTypes.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHbmTypes.java
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/biometrics/HbmTypes.java
rename to packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHbmTypes.java
index f798005..3ab0bd6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/HbmTypes.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHbmTypes.java
@@ -25,7 +25,7 @@
 /**
  * Different high-brightness mode (HBM) types that are relevant to this package.
  */
-public final class HbmTypes {
+public final class UdfpsHbmTypes {
     /** HBM that applies to the whole screen. */
     public static final int GLOBAL_HBM = IUdfpsHbmListener.GLOBAL_HBM;
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsIlluminator.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsIlluminator.java
index 8bea05b..1676bcd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsIlluminator.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsIlluminator.java
@@ -26,7 +26,7 @@
     /**
      * @param callback Invoked when HBM should be enabled or disabled.
      */
-    void setHbmCallback(@Nullable HbmCallback callback);
+    void setHbmCallback(@Nullable UdfpsHbmCallback callback);
 
     /**
      * Invoked when illumination should start.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
index 4d441bd..aa5f0f6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
@@ -31,7 +31,7 @@
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 
-import com.android.systemui.biometrics.HbmTypes.HbmType;
+import com.android.systemui.biometrics.UdfpsHbmTypes.HbmType;
 
 /**
  * Under-display fingerprint sensor Surface View. The surface should be used for HBM-specific things
@@ -41,7 +41,7 @@
     private static final String TAG = "UdfpsSurfaceView";
     private static final String SETTING_HBM_TYPE =
             "com.android.systemui.biometrics.UdfpsSurfaceView.hbmType";
-    private static final @HbmType int DEFAULT_HBM_TYPE = HbmTypes.GLOBAL_HBM;
+    private static final @HbmType int DEFAULT_HBM_TYPE = UdfpsHbmTypes.GLOBAL_HBM;
 
     /**
      * This is used instead of {@link android.graphics.drawable.Drawable}, because the latter has
@@ -57,7 +57,7 @@
     private final @HbmType int mHbmType;
 
     @NonNull private RectF mSensorRect;
-    @Nullable private HbmCallback mHbmCallback;
+    @Nullable private UdfpsHbmCallback mHbmCallback;
 
     public UdfpsSurfaceView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -90,7 +90,7 @@
     }
 
     @Override
-    public void setHbmCallback(@Nullable HbmCallback callback) {
+    public void setHbmCallback(@Nullable UdfpsHbmCallback callback) {
         mHbmCallback = callback;
     }
 
@@ -102,7 +102,7 @@
             Log.e(TAG, "startIllumination | mHbmCallback is null");
         }
 
-        if (mHbmType == HbmTypes.GLOBAL_HBM) {
+        if (mHbmType == UdfpsHbmTypes.GLOBAL_HBM) {
             drawImmediately(mIlluminationDotDrawable);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index f10d5f3..a1d3040 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -101,7 +101,7 @@
     }
 
     @Override
-    public void setHbmCallback(@Nullable HbmCallback callback) {
+    public void setHbmCallback(@Nullable UdfpsHbmCallback callback) {
         mHbmSurfaceView.setHbmCallback(callback);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index 9d47bbb..f01ac68 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -34,7 +34,7 @@
  */
 public class WirelessChargingAnimation {
 
-    public static final long DURATION = 1133;
+    public static final long DURATION = 1500;
     private static final String TAG = "WirelessChargingView";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 38ffec1..0d3e2ae 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -20,6 +20,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.graphics.Color;
 import android.graphics.PointF;
 import android.util.AttributeSet;
 import android.util.TypedValue;
@@ -42,7 +43,9 @@
  */
 public class WirelessChargingLayout extends FrameLayout {
     public static final int UNKNOWN_BATTERY_LEVEL = -1;
-    private static final long RIPPLE_ANIMATION_DURATION = 1133;
+    private static final long RIPPLE_ANIMATION_DURATION = 1500;
+    private static final int SCRIM_COLOR = 0x4C000000;
+    private static final int SCRIM_FADE_DURATION = 300;
     private ChargingRippleView mRippleView;
 
     public WirelessChargingLayout(Context context) {
@@ -121,6 +124,19 @@
         AnimatorSet animatorSet = new AnimatorSet();
         animatorSet.playTogether(textSizeAnimator, textOpacityAnimator, textFadeAnimator);
 
+        ValueAnimator scrimFadeInAnimator = ObjectAnimator.ofArgb(this,
+                "backgroundColor", Color.TRANSPARENT, SCRIM_COLOR);
+        scrimFadeInAnimator.setDuration(SCRIM_FADE_DURATION);
+        scrimFadeInAnimator.setInterpolator(Interpolators.LINEAR);
+        ValueAnimator scrimFadeOutAnimator = ObjectAnimator.ofArgb(this,
+                "backgroundColor", SCRIM_COLOR, Color.TRANSPARENT);
+        scrimFadeOutAnimator.setDuration(SCRIM_FADE_DURATION);
+        scrimFadeOutAnimator.setInterpolator(Interpolators.LINEAR);
+        scrimFadeOutAnimator.setStartDelay(RIPPLE_ANIMATION_DURATION - SCRIM_FADE_DURATION);
+        AnimatorSet animatorSetScrim = new AnimatorSet();
+        animatorSetScrim.playTogether(scrimFadeInAnimator, scrimFadeOutAnimator);
+        animatorSetScrim.start();
+
         mRippleView = findViewById(R.id.wireless_charging_ripple);
         OnAttachStateChangeListener listener = new OnAttachStateChangeListener() {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 26be987..a904cef 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -120,7 +120,7 @@
     private val onSeedingComplete = Consumer<Boolean> {
         accepted ->
             if (accepted) {
-                selectedStructure = controlsController.get().getFavorites().maxBy {
+                selectedStructure = controlsController.get().getFavorites().maxByOrNull {
                     it.controls.size
                 } ?: EMPTY_STRUCTURE
                 updatePreferences(selectedStructure)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 7fa48d4..1396099 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -29,6 +29,7 @@
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.appops.dagger.AppOpsModule;
 import com.android.systemui.assist.AssistModule;
+import com.android.systemui.biometrics.UdfpsHbmCallback;
 import com.android.systemui.classifier.FalsingModule;
 import com.android.systemui.controls.dagger.ControlsModule;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -160,6 +161,9 @@
     @BindsOptionalOf
     abstract StatusBar optionalStatusBar();
 
+    @BindsOptionalOf
+    abstract UdfpsHbmCallback optionalUdfpsHbmCallback();
+
     @SysUISingleton
     @Binds
     abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index a83b13c..3873c25 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -226,7 +226,7 @@
         ActionsDialog dialog = new ActionsDialog(getContext(), mAdapter, mOverflowAdapter,
                 this::getWalletViewController, mDepthController, mSysuiColorExtractor,
                 mStatusBarService, mNotificationShadeWindowController,
-                mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter);
+                mSysUiState, this::onRotate, isKeyguardShowing(), mPowerAdapter, getEventLogger());
 
         if (shouldShowLockMessage(dialog)) {
             dialog.showLockMessage();
@@ -294,11 +294,11 @@
                 SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
                 NotificationShadeWindowController notificationShadeWindowController,
                 SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
-                MyPowerOptionsAdapter powerAdapter) {
+                MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger) {
             super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions,
                     adapter, overflowAdapter, depthController, sysuiColorExtractor,
                     statusBarService, notificationShadeWindowController, sysuiState,
-                    onRotateCallback, keyguardShowing, powerAdapter);
+                    onRotateCallback, keyguardShowing, powerAdapter, uiEventLogger);
             mWalletFactory = walletFactory;
 
             // Update window attributes
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 2eb3762..f9bb35fc 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -249,7 +249,43 @@
         GA_SCREENSHOT_PRESS(347),
 
         @UiEvent(doc = "The global actions screenshot button was long pressed.")
-        GA_SCREENSHOT_LONG_PRESS(348);
+        GA_SCREENSHOT_LONG_PRESS(348),
+
+        @UiEvent(doc = "The global actions power off button was pressed.")
+        GA_SHUTDOWN_PRESS(802),
+
+        @UiEvent(doc = "The global actions power off button was long pressed.")
+        GA_SHUTDOWN_LONG_PRESS(803),
+
+        @UiEvent(doc = "The global actions reboot button was pressed.")
+        GA_REBOOT_PRESS(349),
+
+        @UiEvent(doc = "The global actions reboot button was long pressed.")
+        GA_REBOOT_LONG_PRESS(804),
+
+        @UiEvent(doc = "The global actions lockdown button was pressed.")
+        GA_LOCKDOWN_PRESS(354), // already created by cwren apparently
+
+        @UiEvent(doc = "Power menu was opened via quick settings button.")
+        GA_OPEN_QS(805),
+
+        @UiEvent(doc = "Power menu was opened via power + volume up.")
+        GA_OPEN_POWER_VOLUP(806),
+
+        @UiEvent(doc = "Power menu was opened via long press on power.")
+        GA_OPEN_LONG_PRESS_POWER(807),
+
+        @UiEvent(doc = "Power menu was closed via long press on power.")
+        GA_CLOSE_LONG_PRESS_POWER(808),
+
+        @UiEvent(doc = "Power menu was dismissed by back gesture.")
+        GA_CLOSE_BACK(809),
+
+        @UiEvent(doc = "Power menu was dismissed by tapping outside dialog.")
+        GA_CLOSE_TAP_OUTSIDE(810),
+
+        @UiEvent(doc = "Power menu was closed via power + volume up.")
+        GA_CLOSE_POWER_VOLUP(811);
 
         private final int mId;
 
@@ -349,6 +385,10 @@
         return mContext;
     }
 
+    protected UiEventLogger getEventLogger() {
+        return mUiEventLogger;
+    }
+
     /**
      * Show the global actions dialog (creating if necessary)
      *
@@ -581,7 +621,7 @@
                 mAdapter, mOverflowAdapter,
                 mDepthController, mSysuiColorExtractor,
                 mStatusBarService, mNotificationShadeWindowController,
-                mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter);
+                mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter, mUiEventLogger);
 
         dialog.setOnDismissListener(this);
         dialog.setOnShowListener(this);
@@ -679,13 +719,14 @@
 
     @VisibleForTesting
     final class ShutDownAction extends SinglePressAction implements LongPressAction {
-        private ShutDownAction() {
+        ShutDownAction() {
             super(R.drawable.ic_lock_power_off,
                     R.string.global_action_power_off);
         }
 
         @Override
         public boolean onLongPress() {
+            mUiEventLogger.log(GlobalActionsEvent.GA_SHUTDOWN_LONG_PRESS);
             if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
                 mWindowManagerFuncs.reboot(true);
                 return true;
@@ -705,6 +746,7 @@
 
         @Override
         public void onPress() {
+            mUiEventLogger.log(GlobalActionsEvent.GA_SHUTDOWN_PRESS);
             // shutdown by making sure radio and power are handled accordingly.
             mWindowManagerFuncs.shutdown();
         }
@@ -807,12 +849,13 @@
 
     @VisibleForTesting
     final class RestartAction extends SinglePressAction implements LongPressAction {
-        private RestartAction() {
+        RestartAction() {
             super(R.drawable.ic_restart, R.string.global_action_restart);
         }
 
         @Override
         public boolean onLongPress() {
+            mUiEventLogger.log(GlobalActionsEvent.GA_REBOOT_LONG_PRESS);
             if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
                 mWindowManagerFuncs.reboot(true);
                 return true;
@@ -832,6 +875,7 @@
 
         @Override
         public void onPress() {
+            mUiEventLogger.log(GlobalActionsEvent.GA_REBOOT_PRESS);
             mWindowManagerFuncs.reboot(false);
         }
     }
@@ -1062,6 +1106,7 @@
         public void onPress() {
             mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
                     UserHandle.USER_ALL);
+            mUiEventLogger.log(GlobalActionsEvent.GA_LOCKDOWN_PRESS);
             try {
                 mIWindowManager.lockNow(null);
                 // Lock profiles (if any) on the background thread.
@@ -2049,6 +2094,7 @@
         private ListPopupWindow mOverflowPopup;
         private Dialog mPowerOptionsDialog;
         protected final Runnable mOnRotateCallback;
+        private UiEventLogger mUiEventLogger;
 
         protected ViewGroup mContainer;
 
@@ -2058,7 +2104,7 @@
                 SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
                 NotificationShadeWindowController notificationShadeWindowController,
                 SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
-                MyPowerOptionsAdapter powerAdapter) {
+                MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger) {
             super(context, themeRes);
             mContext = context;
             mAdapter = adapter;
@@ -2071,6 +2117,7 @@
             mSysUiState = sysuiState;
             mOnRotateCallback = onRotateCallback;
             mKeyguardShowing = keyguardShowing;
+            mUiEventLogger = uiEventLogger;
 
             // Window initialization
             Window window = getWindow();
@@ -2141,7 +2188,7 @@
             mGlobalActionsLayout.setAdapter(mAdapter);
             mContainer = findViewById(com.android.systemui.R.id.global_actions_container);
             mContainer.setOnClickListener(v -> {
-                // TODO: add logging (b/182830510)
+                mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
                 cancel();
             });
 
@@ -2218,6 +2265,12 @@
         }
 
         @Override
+        public void onBackPressed() {
+            super.onBackPressed();
+            mUiEventLogger.log(GlobalActionsEvent.GA_CLOSE_BACK);
+        }
+
+        @Override
         public void show() {
             super.show();
             // split this up so we can override but still call Dialog.show
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index f55f57b..ef53233 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -115,7 +115,7 @@
     private var needsReordering: Boolean = false
     private var keysNeedRemoval = mutableSetOf<String>()
     private var bgColor = getBackgroundColor()
-    private var shouldScrollToActivePlayer: Boolean = false
+    protected var shouldScrollToActivePlayer: Boolean = false
     private var isRtl: Boolean = false
         set(value) {
             if (value != field) {
@@ -184,7 +184,14 @@
                 true /* persistent */)
         mediaManager.addListener(object : MediaDataManager.Listener {
             override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
-                addOrUpdatePlayer(key, oldKey, data)
+                if (addOrUpdatePlayer(key, oldKey, data)) {
+                    MediaPlayerData.getMediaPlayer(key, null)?.let {
+                        logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
+                                it.mInstanceId,
+                                /* isRecommendationCard */ false,
+                                it.surfaceForSmartspaceLogging)
+                    }
+                }
                 val canRemove = data.isPlaying?.let { !it } ?: data.isClearable && !data.active
                 if (canRemove && !Utils.useMediaResumption(context)) {
                     // This view isn't playing, let's remove this! This happens e.g when
@@ -203,6 +210,12 @@
             override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {
                 Log.d(TAG, "My Smartspace media update is here")
                 addSmartspaceMediaRecommendations(key, data)
+                MediaPlayerData.getMediaPlayer(key, null)?.let {
+                    logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
+                            it.mInstanceId,
+                            /* isRecommendationCard */ true,
+                            it.surfaceForSmartspaceLogging)
+                }
                 if (mediaCarouselScrollHandler.visibleToUser) {
                     logSmartspaceImpression()
                 }
@@ -276,7 +289,8 @@
         }
     }
 
-    private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData) {
+    // Returns true if new player is added
+    private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData): Boolean {
         val dataCopy = data.copy(backgroundColor = bgColor)
         val existingPlayer = MediaPlayerData.getMediaPlayer(key, oldKey)
         if (existingPlayer == null) {
@@ -295,7 +309,7 @@
         } else {
             existingPlayer.bindPlayer(dataCopy, key)
             MediaPlayerData.addMediaPlayer(key, dataCopy, existingPlayer)
-            if (visualStabilityManager.isReorderingAllowed) {
+            if (visualStabilityManager.isReorderingAllowed || shouldScrollToActivePlayer) {
                 reorderAllPlayers()
             } else {
                 needsReordering = true
@@ -309,6 +323,7 @@
         if (MediaPlayerData.players().size != mediaContent.childCount) {
             Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync")
         }
+        return existingPlayer == null
     }
 
     private fun addSmartspaceMediaRecommendations(key: String, data: SmartspaceTarget) {
@@ -325,7 +340,7 @@
         val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
             ViewGroup.LayoutParams.WRAP_CONTENT)
         newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
-        newRecs.bindRecommendation(data, bgColor, { v -> shouldScrollToActivePlayer = true })
+        newRecs.bindRecommendation(data, bgColor)
         MediaPlayerData.addMediaRecommendation(key, newRecs)
         updatePlayerToState(newRecs, noAnimation = true)
         reorderAllPlayers()
@@ -649,7 +664,7 @@
 @VisibleForTesting
 internal object MediaPlayerData {
     private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null,
-        emptyList(), emptyList(), "INVALID", null, null, null, false, null)
+        emptyList(), emptyList(), "INVALID", null, null, null, true, null)
 
     data class MediaSortKey(
         // Is Smartspace media recommendation. When the Smartspace media is present, it should
@@ -702,7 +717,7 @@
     /** Returns the index of the first non-timeout media. */
     fun getActiveMediaIndex(): Int {
         mediaPlayers.entries.forEachIndexed { index, e ->
-            if (e.key.data.active) {
+            if (!e.key.isSsMediaRec && e.key.data.active) {
                 return index
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 80f74c4..3e9559b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -25,7 +25,8 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
@@ -277,7 +278,7 @@
                 if (mMediaViewController.isGutsVisible()) return;
 
                 logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
-                        false);
+                        /* isRecommendationCard */ false);
                 mActivityStarter.postStartActivityDismissingKeyguard(clickIntent,
                         buildLaunchAnimatorController(mPlayerViewHolder.getPlayer()));
             });
@@ -385,7 +386,7 @@
                 button.setEnabled(true);
                 button.setOnClickListener(v -> {
                     logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
-                            false);
+                            /* isRecommendationCard */ false);
                     action.run();
                 });
             }
@@ -419,7 +420,7 @@
         mPlayerViewHolder.getDismiss().setEnabled(isDismissible);
         mPlayerViewHolder.getDismiss().setOnClickListener(v -> {
             logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
-                    false);
+                    /* isRecommendationCard */ false);
 
             if (mKey != null) {
                 closeGuts();
@@ -473,10 +474,7 @@
     }
 
     /** Bind this recommendation view based on the data given. */
-    public void bindRecommendation(
-            @NonNull SmartspaceTarget target,
-            @NonNull int backgroundColor,
-            @Nullable View.OnClickListener callback) {
+    public void bindRecommendation(@NonNull SmartspaceTarget target, @NonNull int backgroundColor) {
         if (mRecommendationViewHolder == null) {
             return;
         }
@@ -516,8 +514,9 @@
                 // Get the logo from app's package name when applicable.
                 String packageName = extras.getString(EXTRAS_MEDIA_SOURCE_PACKAGE_NAME);
                 try {
-                    icon = mContext.getPackageManager().getApplicationIcon(
+                    Drawable drawable = mContext.getPackageManager().getApplicationIcon(
                             packageName);
+                    icon = convertToGrayscale(drawable);
                 } catch (PackageManager.NameNotFoundException e) {
                     Log.w(TAG, "No media source icon can be fetched via package name", e);
                 }
@@ -529,18 +528,13 @@
             // Set up media source app's logo.
             ImageView mediaSourceLogoImageView = mediaLogoItems.get(uiComponentIndex);
             mediaSourceLogoImageView.setImageDrawable(icon);
-            // TODO(b/186699032): Tint the app logo using the accent color.
-            mediaSourceLogoImageView.setColorFilter(backgroundColor, PorterDuff.Mode.XOR);
 
             // Set up media item cover.
             ImageView mediaCoverImageView = mediaCoverItems.get(uiComponentIndex);
             mediaCoverImageView.setImageIcon(recommendation.getIcon());
 
             // Set up the click listener if applicable.
-            setSmartspaceRecItemOnClickListener(
-                    mediaCoverImageView,
-                    recommendation,
-                    callback);
+            setSmartspaceRecItemOnClickListener(mediaCoverImageView, recommendation);
 
             if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) {
                 setVisibleAndAlpha(collapsedSet,
@@ -564,7 +558,7 @@
         // Set up long press to show guts setting panel.
         mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
             logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
-                    true);
+                    /* isRecommendationCard */ true);
             closeGuts();
             mKeyguardDismissUtil.executeWhenUnlocked(() -> {
                 mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
@@ -652,6 +646,15 @@
         return (state.getState() == PlaybackState.STATE_PLAYING);
     }
 
+    /** Convert the pass-in source drawable to a grayscale one. */
+    private Drawable convertToGrayscale(Drawable drawable) {
+        ColorMatrix matrix = new ColorMatrix();
+        matrix.setSaturation(0);
+        ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
+        drawable.setColorFilter(filter);
+        return drawable;
+    }
+
     private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
         set.setVisibility(actionId, visible ? ConstraintSet.VISIBLE : ConstraintSet.GONE);
         set.setAlpha(actionId, visible ? 1.0f : 0.0f);
@@ -659,8 +662,7 @@
 
     private void setSmartspaceRecItemOnClickListener(
             @NonNull View view,
-            @NonNull SmartspaceAction action,
-            @Nullable View.OnClickListener callback) {
+            @NonNull SmartspaceAction action) {
         if (view == null || action == null || action.getIntent() == null) {
             Log.e(TAG, "No tap action can be set up");
             return;
@@ -669,7 +671,7 @@
         view.setOnClickListener(v -> {
             // When media recommendation card is shown, it will always be the top card.
             logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
-                    true);
+                    /* isRecommendationCard */ true);
 
             if (shouldSmartspaceRecItemOpenInForeground(action)) {
                 // Request to unlock the device if the activity needs to be opened in foreground.
@@ -683,9 +685,8 @@
                 view.getContext().startActivity(action.getIntent());
             }
 
-            if (callback != null) {
-                callback.onClick(v);
-            }
+            // Automatically scroll to the active player once the media is loaded.
+            mMediaCarouselController.setShouldScrollToActivePlayer(true);
         });
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java
index 2d0d5cd..40f908b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarOverlayController.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.navigationbar;
 
-import android.annotation.ColorInt;
 import android.content.Context;
 import android.view.View;
 
@@ -46,10 +45,9 @@
     }
 
     /**
-     * Initialize the controller with visibility change callback and light/dark icon color.
+     * Initialize the controller with visibility change callback.
      */
-    public void init(Consumer<Boolean> visibilityChangeCallback, @ColorInt int lightIconColor,
-            @ColorInt int darkIconColor) {}
+    public void init(Consumer<Boolean> visibilityChangeCallback) {}
 
     /**
      * Set whether the view can be shown.
@@ -72,11 +70,6 @@
     public void unregisterListeners() {}
 
     /**
-     * Set the dark intensity for all drawables.
-     */
-    public void setDarkIntensity(float darkIntensity) {}
-
-    /**
      * Return the current view.
      */
     public View getCurrentView() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
index fbc7c92..b4f8c10 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
@@ -198,7 +198,6 @@
         }
         mView.getRotationButtonController().setDarkIntensity(darkIntensity);
 
-        Dependency.get(NavigationBarOverlayController.class).setDarkIntensity(darkIntensity);
         for (DarkIntensityListener listener : mDarkIntensityListeners) {
             listener.onDarkIntensity(darkIntensity);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index f82d265d..fcbd596 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -61,7 +61,6 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -326,8 +325,7 @@
         mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
         mNavBarOverlayController = Dependency.get(NavigationBarOverlayController.class);
         if (mNavBarOverlayController.isNavigationBarOverlayEnabled()) {
-            mNavBarOverlayController.init(
-                    mNavbarOverlayVisibilityChangeCallback, mLightIconColor, mDarkIconColor);
+            mNavBarOverlayController.init(mNavbarOverlayVisibilityChangeCallback);
         }
 
         mConfiguration = new Configuration();
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
index 0f66456..b55d86e 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java
@@ -18,7 +18,9 @@
 
 import android.content.ContentProvider;
 import android.content.ContentValues;
+import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Binder;
@@ -27,16 +29,19 @@
 import android.util.Log;
 import android.widget.RemoteViews;
 
+import com.android.systemui.SystemUIAppComponentFactory;
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.shared.system.PeopleProviderUtils;
 
 import javax.inject.Inject;
 
 /** API that returns a People Tile preview. */
-public class PeopleProvider extends ContentProvider {
+public class PeopleProvider extends ContentProvider implements
+        SystemUIAppComponentFactory.ContextInitializer {
     private static final String TAG = "PeopleProvider";
     private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
     private static final String EMPTY_STRING = "";
+    private SystemUIAppComponentFactory.ContextAvailableCallback mCallback;
 
     @Inject
     PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
@@ -82,8 +87,8 @@
             Log.e(TAG, "Could not initialize people widget manager");
             return null;
         }
-        RemoteViews view =
-                mPeopleSpaceWidgetManager.getPreview(shortcutId, userHandle, packageName, extras);
+        RemoteViews view = mPeopleSpaceWidgetManager.getPreview(shortcutId, userHandle, packageName,
+                extras);
         if (view == null) {
             if (DEBUG) Log.d(TAG, "No preview available for shortcutId: " + shortcutId);
             return null;
@@ -130,5 +135,17 @@
     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
         throw new IllegalArgumentException("Invalid method");
     }
+
+    @Override
+    public void attachInfo(Context context, ProviderInfo info) {
+        mCallback.onContextAvailable(context);
+        super.attachInfo(context, info);
+    }
+
+    @Override
+    public void setContextAvailableCallback(
+            SystemUIAppComponentFactory.ContextAvailableCallback callback) {
+        mCallback = callback;
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index dd1a4af..c459963 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -196,13 +196,10 @@
 
     void updateResources(QSPanelController qsPanelController,
             QuickStatusBarHeaderController quickStatusBarHeaderController) {
-        LayoutParams layoutParams = (LayoutParams) mQSPanelContainer.getLayoutParams();
-        layoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.quick_qs_offset_height);
-        mQSPanelContainer.setLayoutParams(layoutParams);
         mQSPanelContainer.setPaddingRelative(
                 mQSPanelContainer.getPaddingStart(),
-                mQSPanelContainer.getPaddingTop(),
+                mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.quick_qs_offset_height),
                 mQSPanelContainer.getPaddingEnd(),
                 mContext.getResources().getDimensionPixelSize(R.dimen.qs_container_bottom_padding)
         );
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 1fa9260..f6d9389 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -29,6 +29,7 @@
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
@@ -73,6 +74,7 @@
     private final View mPowerMenuLite;
     private final boolean mShowPMLiteButton;
     private GlobalActionsDialogLite mGlobalActionsDialog;
+    private final UiEventLogger mUiEventLogger;
 
     private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
             new UserInfoController.OnUserInfoChangedListener() {
@@ -122,6 +124,7 @@
                     startSettingsActivity();
                 }
             } else if (v == mPowerMenuLite) {
+                mUiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS);
                 mGlobalActionsDialog.showOrHideDialog(false, true);
             }
         }
@@ -139,7 +142,7 @@
             QuickQSPanelController quickQSPanelController,
             TunerService tunerService, MetricsLogger metricsLogger, FalsingManager falsingManager,
             @Named(PM_LITE_ENABLED) boolean showPMLiteButton,
-            GlobalActionsDialogLite globalActionsDialog) {
+            GlobalActionsDialogLite globalActionsDialog, UiEventLogger uiEventLogger) {
         super(view);
         mUserManager = userManager;
         mUserInfoController = userInfoController;
@@ -161,6 +164,7 @@
         mPowerMenuLite = mView.findViewById(R.id.pm_lite);
         mShowPMLiteButton = showPMLiteButton;
         mGlobalActionsDialog = globalActionsDialog;
+        mUiEventLogger = uiEventLogger;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 04e32a1..3a6f1d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -190,6 +190,16 @@
                 || vpnName != null || vpnNameWorkProfile != null
                 || isProfileOwnerOfOrganizationOwnedDevice || isParentalControlsEnabled
                 || (hasWorkProfile && isNetworkLoggingEnabled);
+        // Update the view to be untappable if the device is an organization-owned device with a
+        // managed profile and there is no policy set which requires a privacy disclosure.
+        if (mIsVisible && isProfileOwnerOfOrganizationOwnedDevice && !isNetworkLoggingEnabled
+                && !hasCACertsInWorkProfile && vpnNameWorkProfile == null) {
+            mRootView.setClickable(false);
+            mRootView.findViewById(R.id.footer_icon).setVisibility(View.GONE);
+        } else {
+            mRootView.setClickable(true);
+            mRootView.findViewById(R.id.footer_icon).setVisibility(View.VISIBLE);
+        }
         // Update the string
         mFooterTextContent = getFooterText(isDeviceManaged, hasWorkProfile,
                 hasCACerts, hasCACertsInWorkProfile, isNetworkLoggingEnabled, vpnName,
@@ -345,20 +355,15 @@
 
     private View createOrganizationDialogView() {
         final boolean isDeviceManaged = mSecurityController.isDeviceManaged();
-        boolean isProfileOwnerOfOrganizationOwnedDevice =
-                mSecurityController.isProfileOwnerOfOrganizationOwnedDevice();
         final boolean hasWorkProfile = mSecurityController.hasWorkProfile();
         final CharSequence deviceOwnerOrganization =
                 mSecurityController.getDeviceOwnerOrganizationName();
-        final CharSequence workProfileOrganizationName =
-                mSecurityController.getWorkProfileOrganizationName();
         final boolean hasCACerts = mSecurityController.hasCACertInCurrentUser();
         final boolean hasCACertsInWorkProfile = mSecurityController.hasCACertInWorkProfile();
         final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
         final String vpnName = mSecurityController.getPrimaryVpnName();
         final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName();
 
-
         View dialogView = LayoutInflater.from(mContext)
                 .inflate(R.layout.quick_settings_footer_dialog, null, false);
 
@@ -368,8 +373,7 @@
         deviceManagementSubtitle.setText(getManagementTitle(deviceOwnerOrganization));
 
         CharSequence managementMessage = getManagementMessage(isDeviceManaged,
-                deviceOwnerOrganization, isProfileOwnerOfOrganizationOwnedDevice,
-                workProfileOrganizationName);
+                deviceOwnerOrganization);
         if (managementMessage == null) {
             dialogView.findViewById(R.id.device_management_disclosures).setVisibility(View.GONE);
         } else {
@@ -377,11 +381,7 @@
             TextView deviceManagementWarning =
                     (TextView) dialogView.findViewById(R.id.device_management_warning);
             deviceManagementWarning.setText(managementMessage);
-            // Don't show the policies button for profile owner of org owned device, because there
-            // is no policies settings screen for it
-            if (!isProfileOwnerOfOrganizationOwnedDevice) {
-                mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
-            }
+            mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
         }
 
         // ca certificate section
@@ -496,12 +496,11 @@
     }
 
     protected CharSequence getManagementMessage(boolean isDeviceManaged,
-            CharSequence organizationName, boolean isProfileOwnerOfOrganizationOwnedDevice,
-            CharSequence workProfileOrganizationName) {
-        if (!isDeviceManaged && !isProfileOwnerOfOrganizationOwnedDevice) {
+            CharSequence organizationName) {
+        if (!isDeviceManaged) {
             return null;
         }
-        if (isDeviceManaged && organizationName != null) {
+        if (organizationName != null) {
             if (isFinancedDevice()) {
                 return mContext.getString(R.string.monitoring_financed_description_named_management,
                         organizationName, organizationName);
@@ -509,9 +508,6 @@
                 return mContext.getString(
                         R.string.monitoring_description_named_management, organizationName);
             }
-        } else if (isProfileOwnerOfOrganizationOwnedDevice && workProfileOrganizationName != null) {
-            return mContext.getString(
-                    R.string.monitoring_description_named_management, workProfileOrganizationName);
         }
         return mContext.getString(R.string.monitoring_description_management);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 73a6b34..26332f4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -23,7 +23,6 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.MathUtils;
 import android.util.Pair;
 import android.view.DisplayCutout;
 import android.view.View;
@@ -36,9 +35,7 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.qs.QSDetail.Callback;
-import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
 import com.android.systemui.statusbar.phone.StatusBarWindowView;
 import com.android.systemui.statusbar.phone.StatusIconContainer;
@@ -67,7 +64,11 @@
 
     private View mQSCarriers;
     private Clock mClockView;
-    private Space mSpace;
+    private Space mDatePrivacySeparator;
+    private View mClockIconsSeparator;
+    private boolean mShowClockIconsSeparator;
+    private ViewGroup mRightLayout;
+
     private BatteryMeterView mBatteryRemainingIcon;
     private StatusIconContainer mIconContainer;
     private View mPrivacyChip;
@@ -80,7 +81,7 @@
     private int mWaterfallTopInset;
     private int mCutOutPaddingLeft;
     private int mCutOutPaddingRight;
-    private float mClockIconsAlpha = 1.0f;
+    private float mViewAlpha = 1.0f;
     private float mKeyguardExpansionFraction;
     private int mTextColorPrimary = Color.TRANSPARENT;
     private int mTopViewMeasureHeight;
@@ -117,9 +118,11 @@
         mPrivacyChip = findViewById(R.id.privacy_chip);
         mDateView = findViewById(R.id.date);
         mSecurityHeaderView = findViewById(R.id.header_text_container);
+        mClockIconsSeparator = findViewById(R.id.separator);
+        mRightLayout = findViewById(R.id.rightLayout);
 
         mClockView = findViewById(R.id.clock);
-        mSpace = findViewById(R.id.space);
+        mDatePrivacySeparator = findViewById(R.id.space);
         // Tint for the battery icons are handled in setupHost()
         mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
 
@@ -230,36 +233,36 @@
     }
 
     private void updateAlphaAnimator() {
-        StatusBarIconView noCallingIcon =
-                ((StatusBarIconView) mIconContainer.getViewForSlot(mMobileSlotName));
-        StatusBarIconView callStrengthIcon =
-                ((StatusBarIconView) mIconContainer.getViewForSlot(mCallStrengthSlotName));
         TouchAnimator.Builder builder = new TouchAnimator.Builder()
                 // The following two views have to be hidden manually, so as not to hide the
                 // Privacy chip in QQS
                 .addFloat(mDateView, "alpha", 0, 1)
                 .addFloat(mSecurityHeaderView, "alpha", 0, 1)
-                .addFloat(mQSCarriers, "alpha", 0, 1);
-        builder.setListener(new TouchAnimator.ListenerAdapter() {
-            @Override
-            public void onAnimationAtEnd() {
-                mIconContainer.addIgnoredSlot(mMobileSlotName);
-                mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
-            }
+                .addFloat(mQSCarriers, "alpha", 0, 1)
+                .setListener(new TouchAnimator.ListenerAdapter() {
+                    @Override
+                    public void onAnimationAtEnd() {
+                        mIconContainer.addIgnoredSlot(mMobileSlotName);
+                        mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
+                    }
 
-            @Override
-            public void onAnimationStarted() {
-                mIconContainer.addIgnoredSlot(mMobileSlotName);
-                mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
-            }
+                    @Override
+                    public void onAnimationStarted() {
+                        mIconContainer.addIgnoredSlot(mMobileSlotName);
+                        mIconContainer.addIgnoredSlot(mCallStrengthSlotName);
 
-            @Override
-            public void onAnimationAtStart() {
-                super.onAnimationAtStart();
-                mIconContainer.removeIgnoredSlot(mMobileSlotName);
-                mIconContainer.removeIgnoredSlot(mCallStrengthSlotName);
-            }
-        });
+                        setSeparatorVisibility(false);
+                    }
+
+                    @Override
+                    public void onAnimationAtStart() {
+                        super.onAnimationAtStart();
+                        mIconContainer.removeIgnoredSlot(mMobileSlotName);
+                        mIconContainer.removeIgnoredSlot(mCallStrengthSlotName);
+
+                        setSeparatorVisibility(mShowClockIconsSeparator);
+                    }
+                });
         mAlphaAnimator = builder.build();
     }
 
@@ -337,20 +340,30 @@
                         cutout, cornerCutoutPadding, -1);
         mDatePrivacyView.setPadding(padding.first, 0, padding.second, 0);
         mClockIconsView.setPadding(padding.first, 0, padding.second, 0);
-        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSpace.getLayoutParams();
+        LinearLayout.LayoutParams datePrivacySeparatorLayoutParams =
+                (LinearLayout.LayoutParams) mDatePrivacySeparator.getLayoutParams();
+        LinearLayout.LayoutParams mClockIconsSeparatorLayoutParams =
+                (LinearLayout.LayoutParams) mClockIconsSeparator.getLayoutParams();
         boolean cornerCutout = cornerCutoutPadding != null
                 && (cornerCutoutPadding.first == 0 || cornerCutoutPadding.second == 0);
         if (cutout != null) {
             Rect topCutout = cutout.getBoundingRectTop();
             if (topCutout.isEmpty() || cornerCutout) {
-                lp.width = 0;
-                mSpace.setVisibility(View.GONE);
+                datePrivacySeparatorLayoutParams.width = 0;
+                mDatePrivacySeparator.setVisibility(View.GONE);
+                mClockIconsSeparatorLayoutParams.width = 0;
+                setSeparatorVisibility(false);
+                mShowClockIconsSeparator = false;
             } else {
-                lp.width = topCutout.width();
-                mSpace.setVisibility(View.VISIBLE);
+                datePrivacySeparatorLayoutParams.width = topCutout.width();
+                mDatePrivacySeparator.setVisibility(View.VISIBLE);
+                mClockIconsSeparatorLayoutParams.width = topCutout.width();
+                mShowClockIconsSeparator = true;
+                setSeparatorVisibility(mKeyguardExpansionFraction == 0f);
             }
         }
-        mSpace.setLayoutParams(lp);
+        mDatePrivacySeparator.setLayoutParams(datePrivacySeparatorLayoutParams);
+        mClockIconsSeparator.setLayoutParams(mClockIconsSeparatorLayoutParams);
         mCutOutPaddingLeft = padding.first;
         mCutOutPaddingRight = padding.second;
         mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
@@ -358,6 +371,32 @@
         return super.onApplyWindowInsets(insets);
     }
 
+    /**
+     * Sets the visibility of the separator between clock and icons.
+     *
+     * This separator is "visible" when there is a center cutout, to block that space. In that
+     * case, the clock and the layout on the right (containing the icons and the battery meter) are
+     * set to weight 1 to take the available space.
+     * @param visible whether the separator between clock and icons should be visible.
+     */
+    private void setSeparatorVisibility(boolean visible) {
+        int newVisibility = visible ? View.VISIBLE : View.GONE;
+        if (mClockIconsSeparator.getVisibility() == newVisibility) return;
+
+        mClockIconsSeparator.setVisibility(visible ? View.VISIBLE : View.GONE);
+        mQSCarriers.setVisibility(visible ? View.GONE : View.VISIBLE);
+
+        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mClockView.getLayoutParams();
+        lp.width = visible ? 0 : WRAP_CONTENT;
+        lp.weight = visible ? 1f : 0f;
+        mClockView.setLayoutParams(lp);
+
+        lp = (LinearLayout.LayoutParams) mRightLayout.getLayoutParams();
+        lp.width = visible ? 0 : WRAP_CONTENT;
+        lp.weight = visible ? 1f : 0f;
+        mRightLayout.setLayoutParams(lp);
+    }
+
     private void updateHeadersPadding() {
         setContentMargins(mDatePrivacyView, 0, 0);
         setContentMargins(mClockIconsView, 0, 0);
@@ -408,35 +447,12 @@
     }
 
     /**
-     * When QS is scrolling, mClockIconsAlpha should scroll away and fade out.
-     *
-     * For a given scroll level, this method does the following:
-     * <ol>
-     *     <li>Determine the alpha that {@code mClockIconsView} should have when the panel is fully
-     *         expanded.</li>
-     *     <li>Set the scroll of {@code mClockIconsView} to the same of {@code QSPanel}.</li>
-     *     <li>Set the alpha of {@code mClockIconsView} to that determined by the expansion of
-     *         the panel, interpolated between 1 (no expansion) and {@code mClockIconsAlpha} (fully
-     *         expanded), matching the animator.</li>
-     * </ol>
+     * Scroll the headers away.
      *
      * @param scrollY the scroll of the QSPanel container
      */
     public void setExpandedScrollAmount(int scrollY) {
-        // The scrolling of the expanded qs has changed. Since the header text isn't part of it,
-        // but would overlap content, we're fading it out.
-        float newAlpha = 1.0f;
-        if (mClockIconsView.getHeight() > 0) {
-            newAlpha = MathUtils.map(0, mClockIconsView.getHeight() / 2.0f, 1.0f, 0.0f,
-                    scrollY);
-            newAlpha = Interpolators.ALPHA_OUT.getInterpolation(newAlpha);
-        }
         mClockIconsView.setScrollY(scrollY);
-        if (newAlpha != mClockIconsAlpha) {
-            mClockIconsAlpha = newAlpha;
-            mClockIconsView.setAlpha(MathUtils.lerp(1.0f, mClockIconsAlpha,
-                    mKeyguardExpansionFraction));
-            updateAlphaAnimator();
-        }
+        mDatePrivacyView.setScrollY(scrollY);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 2d777a5..b3ec39f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tileimpl
 
+import android.animation.ArgbEvaluator
+import android.animation.PropertyValuesHolder
 import android.animation.ValueAnimator
 import android.content.Context
 import android.content.res.ColorStateList
@@ -43,6 +45,7 @@
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.plugins.qs.QSTile.BooleanState
 import com.android.systemui.plugins.qs.QSTileView
+import com.android.systemui.qs.tileimpl.QSIconViewImpl.QS_ANIM_LENGTH
 import java.util.Objects
 
 private const val TAG = "QSTileViewImpl"
@@ -54,6 +57,10 @@
 
     companion object {
         private const val INVALID = -1
+        private const val BACKGROUND_NAME = "background"
+        private const val LABEL_NAME = "label"
+        private const val SECONDARY_LABEL_NAME = "secondaryLabel"
+        private const val CHEVRON_NAME = "chevron"
     }
 
     override var heightOverride: Int = HeightOverrideable.NO_OVERRIDE
@@ -83,9 +90,19 @@
     private lateinit var ripple: RippleDrawable
     private lateinit var colorBackgroundDrawable: Drawable
     private var paintColor: Int = 0
-    private var paintAnimator: ValueAnimator? = null
-    private var labelAnimator: ValueAnimator? = null
-    private var secondaryLabelAnimator: ValueAnimator? = null
+    private val singleAnimator: ValueAnimator = ValueAnimator().apply {
+        setDuration(QS_ANIM_LENGTH)
+        addUpdateListener { animation ->
+            setAllColors(
+                // These casts will throw an exception if some property is missing. We should
+                // always have all properties.
+                animation.getAnimatedValue(BACKGROUND_NAME) as Int,
+                animation.getAnimatedValue(LABEL_NAME) as Int,
+                animation.getAnimatedValue(SECONDARY_LABEL_NAME) as Int,
+                animation.getAnimatedValue(CHEVRON_NAME) as Int
+            )
+        }
+    }
 
     private var accessibilityClass: String? = null
     private var stateDescriptionDeltas: CharSequence? = null
@@ -104,8 +121,7 @@
         clipToPadding = false
         isFocusable = true
         background = createTileBackground()
-        paintColor = getCircleColor(QSTile.State.DEFAULT_STATE)
-        colorBackgroundDrawable.setTint(paintColor)
+        setColor(getBackgroundColorForState(QSTile.State.DEFAULT_STATE))
 
         val padding = resources.getDimensionPixelSize(R.dimen.qs_tile_padding)
         val startPadding = resources.getDimensionPixelSize(R.dimen.qs_tile_start_padding)
@@ -166,8 +182,8 @@
             labelContainer.ignoreLastView = true
             secondaryLabel.alpha = 0f
         }
-        label.setTextColor(getLabelColor(QSTile.State.DEFAULT_STATE))
-        secondaryLabel.setTextColor(getSecondaryLabelColor(QSTile.State.DEFAULT_STATE))
+        setLabelColor(getLabelColorForState(QSTile.State.DEFAULT_STATE))
+        setSecondaryLabelColor(getSecondaryLabelColorForState(QSTile.State.DEFAULT_STATE))
         addView(labelContainer)
     }
 
@@ -176,6 +192,7 @@
                 .inflate(R.layout.qs_tile_side_icon, this, false) as ViewGroup
         customDrawableView = sideView.requireViewById(R.id.customDrawable)
         chevronView = sideView.requireViewById(R.id.chevron)
+        setChevronColor(getChevronColorForState(QSTile.State.DEFAULT_STATE))
         addView(sideView)
     }
 
@@ -322,19 +339,6 @@
         icon.setIcon(state, allowAnimations)
         contentDescription = state.contentDescription
 
-        // Background color animation
-        val newColor = getCircleColor(state.state)
-        if (allowAnimations) {
-            animateBackground(newColor)
-        } else {
-            clearBackgroundAnimator()
-            colorBackgroundDrawable.setTintList(ColorStateList.valueOf(newColor)).also {
-                paintColor = newColor
-            }
-            paintColor = newColor
-        }
-        //
-
         // State handling and description
         val stateDescription = StringBuilder()
         val stateText = getStateText(state)
@@ -383,23 +387,80 @@
             }
         }
 
-        if (allowAnimations) {
-            animateLabelColor(getLabelColor(state.state))
-            animateSecondaryLabelColor(getSecondaryLabelColor(state.state))
-        } else {
-            label.setTextColor(getLabelColor(state.state))
-            secondaryLabel.setTextColor(getSecondaryLabelColor(state.state))
+        // Colors
+        if (state.state != lastState) {
+            singleAnimator.cancel()
+            if (allowAnimations) {
+                singleAnimator.setValues(
+                        colorValuesHolder(
+                                BACKGROUND_NAME,
+                                paintColor,
+                                getBackgroundColorForState(state.state)
+                        ),
+                        colorValuesHolder(
+                                LABEL_NAME,
+                                label.currentTextColor,
+                                getLabelColorForState(state.state)
+                        ),
+                        colorValuesHolder(
+                                SECONDARY_LABEL_NAME,
+                                label.currentTextColor,
+                                getSecondaryLabelColorForState(state.state)
+                        ),
+                        colorValuesHolder(
+                                CHEVRON_NAME,
+                                chevronView.imageTintList?.defaultColor ?: 0,
+                                getChevronColorForState(state.state)
+                        )
+                    )
+                singleAnimator.start()
+            } else {
+                setAllColors(
+                    getBackgroundColorForState(state.state),
+                    getLabelColorForState(state.state),
+                    getLabelColorForState(state.state),
+                    getChevronColorForState(state.state)
+                )
+            }
         }
 
         // Right side icon
         loadSideViewDrawableIfNecessary(state)
-        chevronView.imageTintList = ColorStateList.valueOf(getSecondaryLabelColor(state.state))
 
         label.isEnabled = !state.disabledByPolicy
 
         lastState = state.state
     }
 
+    private fun setAllColors(
+        backgroundColor: Int,
+        labelColor: Int,
+        secondaryLabelColor: Int,
+        chevronColor: Int
+    ) {
+        setColor(backgroundColor)
+        setLabelColor(labelColor)
+        setSecondaryLabelColor(secondaryLabelColor)
+        setChevronColor(chevronColor)
+    }
+
+    private fun setColor(color: Int) {
+        colorBackgroundDrawable.setTint(color)
+        paintColor = color
+    }
+
+    private fun setLabelColor(color: Int) {
+        label.setTextColor(color)
+    }
+
+    private fun setSecondaryLabelColor(color: Int) {
+        secondaryLabel.setTextColor(color)
+    }
+
+    private fun setChevronColor(color: Int) {
+        chevronView.imageTintList = ColorStateList.valueOf(color)
+    }
+
     private fun loadSideViewDrawableIfNecessary(state: QSTile.State) {
         if (state.sideViewCustomDrawable != null) {
             customDrawableView.setImageDrawable(state.sideViewCustomDrawable)
@@ -446,63 +507,7 @@
         return locInScreen.get(1) >= -height
     }
 
-    private fun animateBackground(newBackgroundColor: Int) {
-        if (newBackgroundColor != paintColor) {
-            clearBackgroundAnimator()
-            paintAnimator = ValueAnimator.ofArgb(paintColor, newBackgroundColor)
-                    .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
-                        addUpdateListener { animation: ValueAnimator ->
-                            val c = animation.animatedValue as Int
-                            colorBackgroundDrawable.setTintList(ColorStateList.valueOf(c)).also {
-                                paintColor = c
-                            }
-                        }
-                        start()
-                    }
-        }
-    }
-
-    private fun animateLabelColor(color: Int) {
-        val currentColor = label.textColors.defaultColor
-        if (currentColor != color) {
-            clearLabelAnimator()
-            labelAnimator = ValueAnimator.ofArgb(currentColor, color)
-                    .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
-                        addUpdateListener {
-                            label.setTextColor(it.animatedValue as Int)
-                        }
-                        start()
-                    }
-        }
-    }
-
-    private fun animateSecondaryLabelColor(color: Int) {
-        val currentColor = secondaryLabel.textColors.defaultColor
-        if (currentColor != color) {
-            clearSecondaryLabelAnimator()
-            secondaryLabelAnimator = ValueAnimator.ofArgb(currentColor, color)
-                    .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
-                        addUpdateListener {
-                            secondaryLabel.setTextColor(it.animatedValue as Int)
-                        }
-                        start()
-                    }
-        }
-    }
-
-    private fun clearBackgroundAnimator() {
-        paintAnimator?.cancel()?.also { paintAnimator = null }
-    }
-
-    private fun clearLabelAnimator() {
-        labelAnimator?.cancel()?.also { labelAnimator = null }
-    }
-
-    private fun clearSecondaryLabelAnimator() {
-        secondaryLabelAnimator?.cancel()?.also { secondaryLabelAnimator = null }
-    }
-
-    private fun getCircleColor(state: Int): Int {
+    private fun getBackgroundColorForState(state: Int): Int {
         return when (state) {
             Tile.STATE_ACTIVE -> colorActive
             Tile.STATE_INACTIVE -> colorInactive
@@ -514,7 +519,7 @@
         }
     }
 
-    private fun getLabelColor(state: Int): Int {
+    private fun getLabelColorForState(state: Int): Int {
         return when (state) {
             Tile.STATE_ACTIVE -> colorLabelActive
             Tile.STATE_INACTIVE -> colorLabelInactive
@@ -526,7 +531,7 @@
         }
     }
 
-    private fun getSecondaryLabelColor(state: Int): Int {
+    private fun getSecondaryLabelColorForState(state: Int): Int {
         return when (state) {
             Tile.STATE_ACTIVE -> colorLabelActive
             Tile.STATE_INACTIVE, Tile.STATE_UNAVAILABLE -> colorLabelUnavailable
@@ -536,4 +541,12 @@
             }
         }
     }
+
+    private fun getChevronColorForState(state: Int): Int = getSecondaryLabelColorForState(state)
+}
+
+private fun colorValuesHolder(name: String, vararg values: Int): PropertyValuesHolder {
+    return PropertyValuesHolder.ofInt(name, *values).apply {
+        setEvaluator(ArgbEvaluator.getInstance())
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index fa28754..30c9b44 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -22,7 +22,6 @@
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.HardwareRenderer;
-import android.graphics.Matrix;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RenderNode;
@@ -35,7 +34,6 @@
 import android.util.Log;
 import android.view.ScrollCaptureResponse;
 import android.view.View;
-import android.view.Window;
 import android.widget.ImageView;
 
 import androidx.constraintlayout.widget.ConstraintLayout;
@@ -68,8 +66,6 @@
     public static final String EXTRA_CAPTURE_RESPONSE = "capture-response";
     private static final String KEY_SAVED_IMAGE_PATH = "saved-image-path";
 
-    private static final boolean USE_SHARED_ELEMENT = false;
-
     private final UiEventLogger mUiEventLogger;
     private final Executor mUiExecutor;
     private final Executor mBackgroundExecutor;
@@ -89,6 +85,7 @@
     private ListenableFuture<File> mCacheSaveFuture;
     private ListenableFuture<ImageLoader.Result> mCacheLoadFuture;
 
+    private Bitmap mOutputBitmap;
     private LongScreenshot mLongScreenshot;
     private boolean mTransitionStarted;
 
@@ -114,7 +111,7 @@
     public void onCreate(Bundle savedInstanceState) {
         Log.d(TAG, "onCreate(savedInstanceState = " + savedInstanceState + ")");
         super.onCreate(savedInstanceState);
-        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
+
         setContentView(R.layout.long_screenshot);
 
         mPreview = requireViewById(R.id.preview);
@@ -173,7 +170,6 @@
                 }
             }, mUiExecutor);
             mCacheLoadFuture = null;
-            return;
         } else {
             LongScreenshot longScreenshot = mLongScreenshotHolder.takeLongScreenshot();
             if (longScreenshot != null) {
@@ -189,7 +185,6 @@
         Log.d(TAG, "onLongScreenshotReceived(longScreenshot=" + longScreenshot + ")");
         mLongScreenshot = longScreenshot;
         mPreview.setImageDrawable(mLongScreenshot.getDrawable());
-        mTransitionView.setImageDrawable(mLongScreenshot.getDrawable());
         updateImageDimensions();
         mCropView.setVisibility(View.VISIBLE);
         mMagnifierView.setDrawable(mLongScreenshot.getDrawable(),
@@ -310,19 +305,15 @@
         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
 
-        if (USE_SHARED_ELEMENT) {
-            updateImageDimensions();
-            mTransitionView.setVisibility(View.VISIBLE);
-            // TODO: listen for transition completing instead of finishing onStop
-            mTransitionStarted = true;
-            startActivity(intent,
-                    ActivityOptions.makeSceneTransitionAnimation(this, mTransitionView,
-                            ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle());
-        } else {
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            startActivityAsUser(intent, UserHandle.CURRENT);
-            finishAndRemoveTask();
-        }
+        mTransitionView.setImageBitmap(mOutputBitmap);
+        mTransitionView.setVisibility(View.VISIBLE);
+        mTransitionView.setTransitionName(
+                ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME);
+        // TODO: listen for transition completing instead of finishing onStop
+        mTransitionStarted = true;
+        startActivity(intent,
+                ActivityOptions.makeSceneTransitionAnimation(this, mTransitionView,
+                        ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle());
     }
 
     private void doShare(Uri uri) {
@@ -368,9 +359,11 @@
             return;
         }
 
-        Bitmap output = renderBitmap(mPreview.getDrawable(), bounds);
+        updateImageDimensions();
+
+        mOutputBitmap = renderBitmap(drawable, bounds);
         ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
-                mBackgroundExecutor, UUID.randomUUID(), output, ZonedDateTime.now());
+                mBackgroundExecutor, UUID.randomUUID(), mOutputBitmap, ZonedDateTime.now());
         exportFuture.addListener(() -> onExportCompleted(action, exportFuture), mUiExecutor);
     }
 
@@ -419,7 +412,6 @@
         // The image width and height on screen
         int imageHeight = previewHeight;
         int imageWidth = previewWidth;
-        float scale;
         if (imageRatio > viewRatio) {
             // Image is full width and height is constrained, compute extra padding to inform
             // CropView
@@ -428,15 +420,13 @@
             mCropView.setExtraPadding(extraPadding + mPreview.getPaddingTop(),
                     extraPadding + mPreview.getPaddingBottom());
             imageTop += (previewHeight - imageHeight) / 2;
-            scale = imageHeight / bounds.height();
             mCropView.setExtraPadding(extraPadding, extraPadding);
             mCropView.setImageWidth(previewWidth);
         } else {
             imageWidth = (int) (previewWidth * imageRatio / viewRatio);
             imageLeft += (previewWidth - imageWidth) / 2;
-            scale = imageWidth / (float) bounds.width();
             // Image is full height
-            mCropView.setExtraPadding(mPreview.getPaddingTop(),  mPreview.getPaddingBottom());
+            mCropView.setExtraPadding(mPreview.getPaddingTop(), mPreview.getPaddingBottom());
             mCropView.setImageWidth((int) (previewHeight * imageRatio));
         }
 
@@ -449,10 +439,5 @@
         params.width = boundaries.width();
         params.height = boundaries.height();
         mTransitionView.setLayoutParams(params);
-
-        Matrix matrix = new Matrix();
-        matrix.postScale(scale, scale, 0, 0);
-        matrix.postTranslate(-boundaries.left, -boundaries.top);
-        mTransitionView.setImageMatrix(matrix);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 1ff30a3..6baacb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -57,6 +57,7 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.GcUtils;
 import com.android.internal.view.AppearanceRegion;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.commandline.CommandRegistry;
@@ -1086,6 +1087,12 @@
         thr.start();
     }
 
+    @Override
+    public void runGcForTest() {
+        // Gc sysui
+        GcUtils.runGcAndFinalizersSync();
+    }
+
     private final class H extends Handler {
         private H(Looper l) {
             super(l);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 7f31fdd..5437ce6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.statusbar.RemoteInputController.processForRemoteInput;
 import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
-import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
 
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
@@ -35,6 +34,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.dagger.StatusBarModule;
 import com.android.systemui.statusbar.phone.NotificationListenerWithPlugins;
+import com.android.systemui.statusbar.phone.StatusBar;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -46,6 +46,7 @@
 @SuppressLint("OverrideAbstract")
 public class NotificationListener extends NotificationListenerWithPlugins {
     private static final String TAG = "NotificationListener";
+    private static final boolean DEBUG = StatusBar.DEBUG;
 
     private final Context mContext;
     private final NotificationManager mNotificationManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 70b3a7b..ca81a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -169,7 +169,7 @@
                     Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view);
                     mLogger.logStartingIntentWithDefaultHandler(entry, pendingIntent);
                     boolean started = RemoteViews.startPendingIntent(view, pendingIntent, options);
-                    if (started) releaseNotificationIfKeptForRemoteInputHistory(entry.getKey());
+                    if (started) releaseNotificationIfKeptForRemoteInputHistory(entry);
                     return started;
             });
         }
@@ -608,7 +608,11 @@
      * (after unlock, if applicable), and will then wait a short time to allow the app to update the
      * notification in response to the action.
      */
-    private void releaseNotificationIfKeptForRemoteInputHistory(String key) {
+    private void releaseNotificationIfKeptForRemoteInputHistory(NotificationEntry entry) {
+        if (entry == null) {
+            return;
+        }
+        final String key = entry.getKey();
         if (isNotificationKeptForRemoteInputHistory(key)) {
             mMainHandler.postDelayed(() -> {
                 if (isNotificationKeptForRemoteInputHistory(key)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index 2481ed4..5f10e55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -29,13 +29,11 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED
 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher
 import com.android.systemui.statusbar.phone.StatusBarMarginUpdatedListener
 import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE
-import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE
-import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
-import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
 
 import java.lang.IllegalStateException
 import java.util.concurrent.Executor
@@ -50,7 +48,7 @@
  * will have its gravity set towards the corner (i.e., top-right corner gets top|right gravity), and
  * the contained ImageView will be set to center_vertical and away from the corner horizontally. The
  * Views will match the status bar top padding and status bar height so that the dot can appear to
- * reside directly after the status bar system contents (basically to the right of the battery).
+ * reside directly after the status bar system contents (basically after the battery).
  *
  * NOTE: any operation that modifies views directly must run on the provided executor, because
  * these views are owned by ScreenDecorations and it runs in its own thread
@@ -85,21 +83,27 @@
 
     // Privacy dots are created in ScreenDecoration's UiThread, which is not the main thread
     private var uiExecutor: DelayableExecutor? = null
-    private var e: DelayableExecutor? = null
+
+    private val marginListener: StatusBarMarginUpdatedListener =
+            object : StatusBarMarginUpdatedListener {
+        override fun onStatusBarMarginUpdated(marginLeft: Int, marginRight: Int) {
+            setStatusBarMargins(marginLeft, marginRight)
+        }
+    }
 
     private val views: Sequence<View>
         get() = if (!this::tl.isInitialized) sequenceOf() else sequenceOf(tl, tr, br, bl)
 
     init {
-        locationPublisher.addCallback(object : StatusBarMarginUpdatedListener {
-            override fun onStatusBarMarginUpdated(marginLeft: Int, marginRight: Int) {
-                setStatusBarMargins(marginLeft, marginRight)
-            }
-        })
+        locationPublisher.addCallback(marginListener)
 
         stateController.addCallback(object : StatusBarStateController.StateListener {
             override fun onExpandedChanged(isExpanded: Boolean) {
-                setStatusBarExpanded(isExpanded)
+                updateStatusBarState()
+            }
+
+            override fun onStateChanged(newState: Int) {
+                updateStatusBarState()
             }
         })
     }
@@ -108,6 +112,13 @@
         uiExecutor = e
     }
 
+    fun setQsExpanded(expanded: Boolean) {
+        dlog("setQsExpanded $expanded")
+        synchronized(lock) {
+            nextViewState = nextViewState.copy(qsExpanded = expanded)
+        }
+    }
+
     @UiThread
     fun setNewRotation(rot: Int) {
         dlog("updateRotation: $rot")
@@ -125,8 +136,8 @@
         val index = newCorner.cornerIndex()
 
         val h = when (rot) {
-            ROTATION_NONE, ROTATION_UPSIDE_DOWN -> sbHeightPortrait
-            ROTATION_LANDSCAPE, ROTATION_SEASCAPE -> sbHeightLandscape
+            0, 2 -> sbHeightPortrait
+            1, 3 -> sbHeightLandscape
             else -> 0
         }
         synchronized(lock) {
@@ -326,15 +337,22 @@
         }
     }
 
-    /**
-     *  We won't show the dot when quick settings is showing
-     */
-    private fun setStatusBarExpanded(expanded: Boolean) {
+    private fun updateStatusBarState() {
         synchronized(lock) {
-            nextViewState = nextViewState.copy(hideDotForQuickSettings = expanded)
+            nextViewState = nextViewState.copy(shadeExpanded = isShadeInQs())
         }
     }
 
+    /**
+     * If we are unlocked with an expanded shade, QS is showing. On keyguard, the shade is always
+     * expanded so we use other signals from the panel view controller to know if QS is expanded
+     */
+    @GuardedBy("lock")
+    private fun isShadeInQs(): Boolean {
+        return (stateController.isExpanded && stateController.state == SHADE) ||
+                (stateController.state == SHADE_LOCKED)
+    }
+
     private fun scheduleUpdate() {
         dlog("scheduleUpdate: ")
 
@@ -431,13 +449,20 @@
     }
 }
 
+private fun vlog(s: String) {
+    if (DEBUG_VERBOSE) {
+        Log.d(TAG, s)
+    }
+}
+
 const val TOP_LEFT = 0
 const val TOP_RIGHT = 1
 const val BOTTOM_RIGHT = 2
 const val BOTTOM_LEFT = 3
 private const val DURATION = 160L
 private const val TAG = "PrivacyDotViewController"
-private const val DEBUG = false
+private const val DEBUG = true
+private const val DEBUG_VERBOSE = false
 
 private fun Int.toGravity(): Int {
     return when (this) {
@@ -460,10 +485,10 @@
 }
 
 private data class ViewState(
-    // don't @ me with names
     val systemPrivacyEventIsActive: Boolean = false,
-    val hideDotForQuickSettings: Boolean = false,
-    val statusBarExpanded: Boolean = false,
+    val shadeExpanded: Boolean = false,
+    val qsExpanded: Boolean = false,
+
     val rotation: Int = 0,
     val height: Int = 0,
     val marginLeft: Int = 0,
@@ -472,7 +497,7 @@
     val designatedCorner: View? = null
 ) {
     fun shouldShowDot(): Boolean {
-        return systemPrivacyEventIsActive && !hideDotForQuickSettings
+        return systemPrivacyEventIsActive && !shadeExpanded && !qsExpanded
     }
 
     fun needsLayout(other: ViewState): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
index d6356de..f40f24a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.statusbar.notification.collection.legacy;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Notification;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
 import android.util.Log;
@@ -31,6 +33,7 @@
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.wm.shell.bubbles.Bubbles;
@@ -39,10 +42,12 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.TreeSet;
 
 import javax.inject.Inject;
 
@@ -58,13 +63,21 @@
 public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener, StateListener,
         GroupMembershipManager, GroupExpansionManager, Dumpable {
 
-    private static final String TAG = "NotificationGroupManager";
+    private static final String TAG = "NotifGroupManager";
+    private static final boolean DEBUG = StatusBar.DEBUG;
+    private static final boolean SPEW = StatusBar.SPEW;
+    /**
+     * The maximum amount of time (in ms) between the posting of notifications that can be
+     * considered part of the same update batch.
+     */
+    private static final long POST_BATCH_MAX_AGE = 5000;
     private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
     private final ArraySet<OnGroupExpansionChangeListener> mExpansionChangeListeners =
             new ArraySet<>();
     private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>();
     private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier;
     private final Optional<Bubbles> mBubblesOptional;
+    private final EventBuffer mEventBuffer = new EventBuffer();
     private int mBarState = -1;
     private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
     private HeadsUpManager mHeadsUpManager;
@@ -134,8 +147,14 @@
      * When we want to remove an entry from being tracked for grouping
      */
     public void onEntryRemoved(NotificationEntry removed) {
+        if (SPEW) {
+            Log.d(TAG, "onEntryRemoved: entry=" + removed);
+        }
         onEntryRemovedInternal(removed, removed.getSbn());
-        mIsolatedEntries.remove(removed.getKey());
+        StatusBarNotification oldSbn = mIsolatedEntries.remove(removed.getKey());
+        if (oldSbn != null) {
+            updateSuppression(mGroupMap.get(oldSbn.getGroupKey()));
+        }
     }
 
     /**
@@ -162,6 +181,9 @@
             // the close future. See b/23676310 for reference.
             return;
         }
+        if (SPEW) {
+            Log.d(TAG, "onEntryRemovedInternal: entry=" + removed + " group=" + group.groupKey);
+        }
         if (isGroupChild(removed.getKey(), isGroup, isGroupSummary)) {
             group.children.remove(removed.getKey());
         } else {
@@ -182,6 +204,9 @@
      * Notify the group manager that a new entry was added
      */
     public void onEntryAdded(final NotificationEntry added) {
+        if (SPEW) {
+            Log.d(TAG, "onEntryAdded: entry=" + added);
+        }
         updateIsolation(added);
         onEntryAddedInternal(added);
     }
@@ -195,13 +220,16 @@
         String groupKey = getGroupKey(sbn);
         NotificationGroup group = mGroupMap.get(groupKey);
         if (group == null) {
-            group = new NotificationGroup();
+            group = new NotificationGroup(groupKey);
             mGroupMap.put(groupKey, group);
 
             for (OnGroupChangeListener listener : mGroupChangeListeners) {
                 listener.onGroupCreated(group, groupKey);
             }
         }
+        if (SPEW) {
+            Log.d(TAG, "onEntryAddedInternal: entry=" + added + " group=" + group.groupKey);
+        }
         if (isGroupChild) {
             NotificationEntry existing = group.children.get(added.getKey());
             if (existing != null && existing != added) {
@@ -213,9 +241,11 @@
                         + " added removed" + added.isRowRemoved(), new Throwable());
             }
             group.children.put(added.getKey(), added);
+            addToPostBatchHistory(group, added);
             updateSuppression(group);
         } else {
             group.summary = added;
+            addToPostBatchHistory(group, added);
             group.expanded = added.areChildrenExpanded();
             updateSuppression(group);
             if (!group.children.isEmpty()) {
@@ -231,6 +261,27 @@
         }
     }
 
+    private void addToPostBatchHistory(NotificationGroup group, @Nullable NotificationEntry entry) {
+        if (entry == null) {
+            return;
+        }
+        boolean didAdd = group.postBatchHistory.add(new PostRecord(entry));
+        if (didAdd) {
+            trimPostBatchHistory(group.postBatchHistory);
+        }
+    }
+
+    /** remove all history that's too old to be in the batch. */
+    private void trimPostBatchHistory(@NonNull TreeSet<PostRecord> postBatchHistory) {
+        if (postBatchHistory.size() <= 1) {
+            return;
+        }
+        long batchStartTime = postBatchHistory.last().postTime - POST_BATCH_MAX_AGE;
+        while (!postBatchHistory.isEmpty() && postBatchHistory.first().postTime < batchStartTime) {
+            postBatchHistory.pollFirst();
+        }
+    }
+
     private void onEntryBecomingChild(NotificationEntry entry) {
         updateIsolation(entry);
     }
@@ -239,6 +290,9 @@
         if (group == null) {
             return;
         }
+        NotificationEntry prevAlertOverride = group.alertOverride;
+        group.alertOverride = getPriorityConversationAlertOverride(group);
+
         int childCount = 0;
         boolean hasBubbles = false;
         for (NotificationEntry entry : group.children.values()) {
@@ -255,18 +309,150 @@
         group.suppressed = group.summary != null && !group.expanded
                 && (childCount == 1
                 || (childCount == 0
-                        && group.summary.getSbn().getNotification().isGroupSummary()
-                        && (hasIsolatedChildren(group) || hasBubbles)));
-        if (prevSuppressed != group.suppressed) {
-            for (OnGroupChangeListener listener : mGroupChangeListeners) {
-                if (!mIsUpdatingUnchangedGroup) {
-                    listener.onGroupSuppressionChanged(group, group.suppressed);
-                    listener.onGroupsChanged();
+                && group.summary.getSbn().getNotification().isGroupSummary()
+                && (hasIsolatedChildren(group) || hasBubbles)));
+
+        boolean alertOverrideChanged = prevAlertOverride != group.alertOverride;
+        boolean suppressionChanged = prevSuppressed != group.suppressed;
+        if (alertOverrideChanged || suppressionChanged) {
+            if (DEBUG && alertOverrideChanged) {
+                Log.d(TAG, "updateSuppression: alertOverride was=" + prevAlertOverride
+                        + " now=" + group.alertOverride + " group:\n" + group);
+            }
+            if (DEBUG && suppressionChanged) {
+                Log.d(TAG,
+                        "updateSuppression: suppressed changed to " + group.suppressed
+                                + " group:\n" + group);
+            }
+            if (!mIsUpdatingUnchangedGroup) {
+                if (alertOverrideChanged) {
+                    mEventBuffer.notifyAlertOverrideChanged(group, prevAlertOverride);
+                }
+                if (suppressionChanged) {
+                    for (OnGroupChangeListener listener : mGroupChangeListeners) {
+                        listener.onGroupSuppressionChanged(group, group.suppressed);
+                    }
+                }
+                mEventBuffer.notifyGroupsChanged();
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, group + " did not notify listeners of above change(s)");
                 }
             }
         }
     }
 
+    /**
+     * Finds the isolated logical child of this group which is should be alerted instead.
+     *
+     * Notifications from priority conversations are isolated from their groups to make them more
+     * prominent, however apps may post these with a GroupAlertBehavior that has the group receiving
+     * the alert.  This would lead to the group alerting even though the conversation that was
+     * updated was not actually a part of that group.  This method finds the best priority
+     * conversation in this situation, if there is one, so they can be set as the alertOverride of
+     * the group.
+     *
+     * @param group the group to check
+     * @return the entry which should receive the alert instead of the group, if any.
+     */
+    @Nullable
+    private NotificationEntry getPriorityConversationAlertOverride(NotificationGroup group) {
+        // GOAL: if there is a priority child which wouldn't alert based on its groupAlertBehavior,
+        // but which should be alerting (because priority conversations are isolated), find it.
+        if (group == null || group.summary == null) {
+            if (SPEW) {
+                Log.d(TAG, "getPriorityConversationAlertOverride: null group or summary");
+            }
+            return null;
+        }
+        if (isIsolated(group.summary.getKey())) {
+            if (SPEW) {
+                Log.d(TAG, "getPriorityConversationAlertOverride: isolated group");
+            }
+            return null;
+        }
+
+        // Precondiions:
+        // * Only necessary when all notifications in the group use GROUP_ALERT_SUMMARY
+        // * Only necessary when at least one notification in the group is on a priority channel
+        if (group.summary.getSbn().getNotification().getGroupAlertBehavior()
+                != Notification.GROUP_ALERT_SUMMARY) {
+            if (SPEW) {
+                Log.d(TAG, "getPriorityConversationAlertOverride: summary != GROUP_ALERT_SUMMARY");
+            }
+            return null;
+        }
+
+        // Get the important children first, copy the keys for the final importance check,
+        // then add the non-isolated children to the map for unified lookup.
+        HashMap<String, NotificationEntry> children = getImportantConversations(group);
+        if (children == null || children.isEmpty()) {
+            if (SPEW) {
+                Log.d(TAG, "getPriorityConversationAlertOverride: no important conversations");
+            }
+            return null;
+        }
+        HashSet<String> importantChildKeys = new HashSet<>(children.keySet());
+        children.putAll(group.children);
+
+        // Ensure all children have GROUP_ALERT_SUMMARY
+        for (NotificationEntry child : children.values()) {
+            if (child.getSbn().getNotification().getGroupAlertBehavior()
+                    != Notification.GROUP_ALERT_SUMMARY) {
+                if (SPEW) {
+                    Log.d(TAG, "getPriorityConversationAlertOverride: "
+                            + "child != GROUP_ALERT_SUMMARY");
+                }
+                return null;
+            }
+        }
+
+        // Create a merged post history from all the children
+        TreeSet<PostRecord> combinedHistory = new TreeSet<>(group.postBatchHistory);
+        for (String importantChildKey : importantChildKeys) {
+            NotificationGroup importantChildGroup = mGroupMap.get(importantChildKey);
+            combinedHistory.addAll(importantChildGroup.postBatchHistory);
+        }
+        trimPostBatchHistory(combinedHistory);
+
+        // This is a streamlined implementation of the following idea:
+        // * From the subset of notifications in the latest 'batch' of updates.  A batch is:
+        //   * Notifs posted less than POST_BATCH_MAX_AGE before the most recently posted.
+        //   * Only including notifs newer than the second-to-last post of any notification.
+        // * Find the newest child in the batch -- the with the largest 'when' value.
+        // * If the newest child is a priority conversation, set that as the override.
+        HashSet<String> batchKeys = new HashSet<>();
+        long newestChildWhen = -1;
+        NotificationEntry newestChild = null;
+        // Iterate backwards through the post history, tracking the child with the smallest sort key
+        for (PostRecord record : combinedHistory.descendingSet()) {
+            if (batchKeys.contains(record.key)) {
+                // Once you see a notification again, the batch has ended
+                break;
+            }
+            batchKeys.add(record.key);
+            NotificationEntry child = children.get(record.key);
+            if (child != null) {
+                long childWhen = child.getSbn().getNotification().when;
+                if (newestChild == null || childWhen > newestChildWhen) {
+                    newestChildWhen = childWhen;
+                    newestChild = child;
+                }
+            }
+        }
+        if (newestChild != null && importantChildKeys.contains(newestChild.getKey())) {
+            if (SPEW) {
+                Log.d(TAG, "getPriorityConversationAlertOverride: result=" + newestChild);
+            }
+            return newestChild;
+        }
+        if (SPEW) {
+            Log.d(TAG, "getPriorityConversationAlertOverride: result=null, newestChild="
+                    + newestChild);
+        }
+        return null;
+    }
+
     private boolean hasIsolatedChildren(NotificationGroup group) {
         return getNumberOfIsolatedChildren(group.summary.getSbn().getGroupKey()) != 0;
     }
@@ -281,12 +467,33 @@
         return count;
     }
 
+    @Nullable
+    private HashMap<String, NotificationEntry> getImportantConversations(NotificationGroup group) {
+        String groupKey = group.summary.getSbn().getGroupKey();
+        HashMap<String, NotificationEntry> result = null;
+        for (StatusBarNotification sbn : mIsolatedEntries.values()) {
+            if (sbn.getGroupKey().equals(groupKey)) {
+                NotificationEntry entry = mGroupMap.get(sbn.getKey()).summary;
+                if (isImportantConversation(entry)) {
+                    if (result == null) {
+                        result = new HashMap<>();
+                    }
+                    result.put(sbn.getKey(), entry);
+                }
+            }
+        }
+        return result;
+    }
+
     /**
      * Update an entry's group information
      * @param entry notification entry to update
      * @param oldNotification previous notification info before this update
      */
     public void onEntryUpdated(NotificationEntry entry, StatusBarNotification oldNotification) {
+        if (SPEW) {
+            Log.d(TAG, "onEntryUpdated: entry=" + entry);
+        }
         onEntryUpdated(entry, oldNotification.getGroupKey(), oldNotification.isGroup(),
                 oldNotification.getNotification().isGroupSummary());
     }
@@ -325,7 +532,17 @@
      * Whether the given notification is the summary of a group that is being suppressed
      */
     public boolean isSummaryOfSuppressedGroup(StatusBarNotification sbn) {
-        return isGroupSuppressed(getGroupKey(sbn)) && sbn.getNotification().isGroupSummary();
+        return sbn.getNotification().isGroupSummary() && isGroupSuppressed(getGroupKey(sbn));
+    }
+
+    /**
+     * If the given notification is a summary, get the group for it.
+     */
+    public NotificationGroup getGroupForSummary(StatusBarNotification sbn) {
+        if (sbn.getNotification().isGroupSummary()) {
+            return mGroupMap.get(getGroupKey(sbn));
+        }
+        return null;
     }
 
     private boolean isOnlyChild(StatusBarNotification sbn) {
@@ -545,9 +762,7 @@
         if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
             return false;
         }
-        int peopleNotificationType =
-                mPeopleNotificationIdentifier.get().getPeopleNotificationType(entry);
-        if (peopleNotificationType == PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON) {
+        if (isImportantConversation(entry)) {
             return true;
         }
         if (mHeadsUpManager != null && !mHeadsUpManager.isAlerting(entry.getKey())) {
@@ -560,18 +775,25 @@
                     || isGroupNotFullyVisible(notificationGroup));
     }
 
+    private boolean isImportantConversation(NotificationEntry entry) {
+        int peopleNotificationType =
+                mPeopleNotificationIdentifier.get().getPeopleNotificationType(entry);
+        return peopleNotificationType == PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON;
+    }
+
     /**
      * Isolate a notification from its group so that it visually shows as its own group.
      *
      * @param entry the notification to isolate
      */
     private void isolateNotification(NotificationEntry entry) {
-        StatusBarNotification sbn = entry.getSbn();
-
+        if (SPEW) {
+            Log.d(TAG, "isolateNotification: entry=" + entry);
+        }
         // We will be isolated now, so lets update the groups
         onEntryRemovedInternal(entry, entry.getSbn());
 
-        mIsolatedEntries.put(sbn.getKey(), sbn);
+        mIsolatedEntries.put(entry.getKey(), entry.getSbn());
 
         onEntryAddedInternal(entry);
         // We also need to update the suppression of the old group, because this call comes
@@ -588,6 +810,14 @@
      * Update the isolation of an entry, splitting it from the group.
      */
     public void updateIsolation(NotificationEntry entry) {
+        // We need to buffer a few events because we do isolation changes in 3 steps:
+        // removeInternal, update mIsolatedEntries, addInternal.  This means that often the
+        // alertOverride will update on the removal, however processing the event in that case can
+        // cause problems because the mIsolatedEntries map is not in its final state, so the event
+        // listener may be unable to correctly determine the true state of the group.  By delaying
+        // the alertOverride change until after the add phase, we can ensure that listeners only
+        // have to handle a consistent state.
+        mEventBuffer.startBuffering();
         boolean isIsolated = isIsolated(entry.getSbn().getKey());
         if (shouldIsolate(entry)) {
             if (!isIsolated) {
@@ -596,6 +826,7 @@
         } else if (isIsolated) {
             stopIsolatingNotification(entry);
         }
+        mEventBuffer.flushAndStopBuffering();
     }
 
     /**
@@ -604,15 +835,15 @@
      * @param entry the notification to un-isolate
      */
     private void stopIsolatingNotification(NotificationEntry entry) {
-        StatusBarNotification sbn = entry.getSbn();
-        if (isIsolated(sbn.getKey())) {
-            // not isolated anymore, we need to update the groups
-            onEntryRemovedInternal(entry, entry.getSbn());
-            mIsolatedEntries.remove(sbn.getKey());
-            onEntryAddedInternal(entry);
-            for (OnGroupChangeListener listener : mGroupChangeListeners) {
-                listener.onGroupsChanged();
-            }
+        if (SPEW) {
+            Log.d(TAG, "stopIsolatingNotification: entry=" + entry);
+        }
+        // not isolated anymore, we need to update the groups
+        onEntryRemovedInternal(entry, entry.getSbn());
+        mIsolatedEntries.remove(entry.getKey());
+        onEntryAddedInternal(entry);
+        for (OnGroupChangeListener listener : mGroupChangeListeners) {
+            listener.onGroupsChanged();
         }
     }
 
@@ -648,33 +879,154 @@
     }
 
     /**
+     * A record of a notification being posted, containing the time of the post and the key of the
+     * notification entry.  These are stored in a TreeSet by the NotificationGroup and used to
+     * calculate a batch of notifications.
+     */
+    public static class PostRecord implements Comparable<PostRecord> {
+        public final long postTime;
+        public final String key;
+
+        /** constructs a record containing the post time and key from the notification entry */
+        public PostRecord(@NonNull NotificationEntry entry) {
+            this.postTime = entry.getSbn().getPostTime();
+            this.key = entry.getKey();
+        }
+
+        @Override
+        public int compareTo(PostRecord o) {
+            int postTimeComparison = Long.compare(this.postTime, o.postTime);
+            return postTimeComparison == 0
+                    ? String.CASE_INSENSITIVE_ORDER.compare(this.key, o.key)
+                    : postTimeComparison;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            PostRecord that = (PostRecord) o;
+            return postTime == that.postTime && key.equals(that.key);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(postTime, key);
+        }
+    }
+
+    /**
      * Represents a notification group in the notification shade.
      */
     public static class NotificationGroup {
+        public final String groupKey;
         public final HashMap<String, NotificationEntry> children = new HashMap<>();
+        public final TreeSet<PostRecord> postBatchHistory = new TreeSet<>();
         public NotificationEntry summary;
         public boolean expanded;
         /**
          * Is this notification group suppressed, i.e its summary is hidden
          */
         public boolean suppressed;
+        /**
+         * The child (which is isolated from this group) to which the alert should be transferred,
+         * due to priority conversations.
+         */
+        public NotificationEntry alertOverride;
+
+        NotificationGroup(String groupKey) {
+            this.groupKey = groupKey;
+        }
 
         @Override
         public String toString() {
-            String result = "    summary:\n      "
-                    + (summary != null ? summary.getSbn() : "null")
-                    + (summary != null && summary.getDebugThrowable() != null
-                            ? Log.getStackTraceString(summary.getDebugThrowable())
-                            : "");
-            result += "\n    children size: " + children.size();
+            StringBuilder sb = new StringBuilder();
+            sb.append("    groupKey: ").append(groupKey);
+            sb.append("\n    summary:");
+            appendEntry(sb, summary);
+            sb.append("\n    children size: ").append(children.size());
             for (NotificationEntry child : children.values()) {
-                result += "\n      " + child.getSbn()
-                        + (child.getDebugThrowable() != null
-                            ? Log.getStackTraceString(child.getDebugThrowable())
-                            : "");
+                appendEntry(sb, child);
             }
-            result += "\n    summary suppressed: " + suppressed;
-            return result;
+            sb.append("\n    alertOverride:");
+            appendEntry(sb, alertOverride);
+            sb.append("\n    summary suppressed: ").append(suppressed);
+            return sb.toString();
+        }
+
+        private void appendEntry(StringBuilder sb, NotificationEntry entry) {
+            sb.append("\n      ").append(entry != null ? entry.getSbn() : "null");
+            if (entry != null && entry.getDebugThrowable() != null) {
+                sb.append(Log.getStackTraceString(entry.getDebugThrowable()));
+            }
+        }
+    }
+
+    /**
+     * This class is a toggleable buffer for a subset of events of {@link OnGroupChangeListener}.
+     * When buffering, instead of notifying the listeners it will set internal state that will allow
+     * it to notify listeners of those events later
+     */
+    private class EventBuffer {
+        private final HashMap<String, NotificationEntry> mOldAlertOverrideByGroup = new HashMap<>();
+        private boolean mIsBuffering = false;
+        private boolean mDidGroupsChange = false;
+
+        void notifyAlertOverrideChanged(NotificationGroup group,
+                NotificationEntry oldAlertOverride) {
+            if (mIsBuffering) {
+                // The value in this map is the override before the event.  If there is an entry
+                // already in the map, then we are effectively coalescing two events, which means
+                // we need to preserve the original initial value.
+                mOldAlertOverrideByGroup.putIfAbsent(group.groupKey, oldAlertOverride);
+            } else {
+                for (OnGroupChangeListener listener : mGroupChangeListeners) {
+                    listener.onGroupAlertOverrideChanged(group, oldAlertOverride,
+                            group.alertOverride);
+                }
+            }
+        }
+
+        void notifyGroupsChanged() {
+            if (mIsBuffering) {
+                mDidGroupsChange = true;
+            } else {
+                for (OnGroupChangeListener listener : mGroupChangeListeners) {
+                    listener.onGroupsChanged();
+                }
+            }
+        }
+
+        void startBuffering() {
+            mIsBuffering = true;
+        }
+
+        void flushAndStopBuffering() {
+            // stop buffering so that we can call our own helpers
+            mIsBuffering = false;
+            // alert all group alert override changes for groups that were not removed
+            for (Map.Entry<String, NotificationEntry> entry : mOldAlertOverrideByGroup.entrySet()) {
+                NotificationGroup group = mGroupMap.get(entry.getKey());
+                if (group == null) {
+                    // The group can be null if this alertOverride changed before the group was
+                    // permanently removed, meaning that there's no guarantee that listeners will
+                    // that field clear.
+                    continue;
+                }
+                NotificationEntry oldAlertOverride = entry.getValue();
+                if (group.alertOverride == oldAlertOverride) {
+                    // If the final alertOverride equals the initial, it means we coalesced two
+                    // events which undid the change, so we can drop it entirely.
+                    continue;
+                }
+                notifyAlertOverrideChanged(group, oldAlertOverride);
+            }
+            mOldAlertOverrideByGroup.clear();
+            // alert that groups changed
+            if (mDidGroupsChange) {
+                notifyGroupsChanged();
+                mDidGroupsChange = false;
+            }
         }
     }
 
@@ -714,6 +1066,18 @@
                 boolean suppressed) {}
 
         /**
+         * The alert override of a group has changed.
+         *
+         * @param group the group that has changed
+         * @param oldAlertOverride the previous notification to which the group's alerts were sent
+         * @param newAlertOverride the notification to which the group's alerts should now be sent
+         */
+        default void onGroupAlertOverrideChanged(
+                NotificationGroup group,
+                @Nullable NotificationEntry oldAlertOverride,
+                @Nullable NotificationEntry newAlertOverride) {}
+
+        /**
          * A group of children just received a summary notification and should therefore become
          * children of it.
          *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 2b51b56..b9fe9c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
 import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
 import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
+import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
 
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
@@ -348,7 +349,8 @@
 
     private void showSystemIconArea(boolean animate) {
         // Only show the system icon area if we are not currently animating
-        if (mAnimationScheduler.getAnimationState() == IDLE) {
+        int state = mAnimationScheduler.getAnimationState();
+        if (state == IDLE || state == SHOWING_PERSISTENT_DOT) {
             animateShow(mSystemIconArea, animate);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index 3181f52..9787a944 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -22,12 +22,12 @@
 import android.os.SystemClock;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
+import android.util.Log;
 
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -41,17 +41,21 @@
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
  * A helper class dealing with the alert interactions between {@link NotificationGroupManagerLegacy}
  * and {@link HeadsUpManager}. In particular, this class deals with keeping
- * the correct notification in a group alerting based off the group suppression.
+ * the correct notification in a group alerting based off the group suppression and alertOverride.
  */
 public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedListener,
         StateListener {
 
     private static final long ALERT_TRANSFER_TIMEOUT = 300;
+    private static final String TAG = "NotifGroupAlertTransfer";
+    private static final boolean DEBUG = StatusBar.DEBUG;
+    private static final boolean SPEW = StatusBar.SPEW;
 
     /**
      * The list of entries containing group alert metadata for each group. Keyed by group key.
@@ -142,41 +146,98 @@
 
         @Override
         public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {
-            if (suppressed) {
-                if (mHeadsUpManager.isAlerting(group.summary.getKey())) {
-                    handleSuppressedSummaryAlerted(group.summary, mHeadsUpManager);
-                }
-            } else {
-                // Group summary can be null if we are no longer suppressed because the summary was
-                // removed. In that case, we don't need to alert the summary.
-                if (group.summary == null) {
-                    return;
-                }
-                GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey(
-                        group.summary.getSbn()));
-                // Group is no longer suppressed. We should check if we need to transfer the alert
-                // back to the summary now that it's no longer suppressed.
-                if (groupAlertEntry.mAlertSummaryOnNextAddition) {
-                    if (!mHeadsUpManager.isAlerting(group.summary.getKey())) {
-                        alertNotificationWhenPossible(group.summary, mHeadsUpManager);
-                    }
-                    groupAlertEntry.mAlertSummaryOnNextAddition = false;
-                } else {
-                    checkShouldTransferBack(groupAlertEntry);
-                }
+            if (DEBUG) {
+                Log.d(TAG, "!! onGroupSuppressionChanged: group.summary=" + group.summary
+                        + " suppressed=" + suppressed);
             }
+            NotificationEntry oldAlertOverride = group.alertOverride;
+            onGroupChanged(group, oldAlertOverride);
+        }
+
+        @Override
+        public void onGroupAlertOverrideChanged(NotificationGroup group,
+                @Nullable NotificationEntry oldAlertOverride,
+                @Nullable NotificationEntry newAlertOverride) {
+            if (DEBUG) {
+                Log.d(TAG, "!! onGroupAlertOverrideChanged: group.summary=" + group.summary
+                        + " oldAlertOverride=" + oldAlertOverride
+                        + " newAlertOverride=" + newAlertOverride);
+            }
+            onGroupChanged(group, oldAlertOverride);
         }
     };
 
-    @Override
-    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-        onAlertStateChanged(entry, isHeadsUp, mHeadsUpManager);
+    /**
+     * Called when either the suppressed or alertOverride fields of the group changed
+     *
+     * @param group the group which changed
+     * @param oldAlertOverride the previous value of group.alertOverride
+     */
+    private void onGroupChanged(NotificationGroup group,
+            NotificationEntry oldAlertOverride) {
+        // Group summary can be null if we are no longer suppressed because the summary was
+        // removed. In that case, we don't need to alert the summary.
+        if (group.summary == null) {
+            if (DEBUG) {
+                Log.d(TAG, "onGroupChanged: summary is null");
+            }
+            return;
+        }
+        if (group.suppressed || group.alertOverride != null) {
+            checkForForwardAlertTransfer(group.summary, oldAlertOverride);
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "onGroupChanged: maybe transfer back");
+            }
+            GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(mGroupManager.getGroupKey(
+                    group.summary.getSbn()));
+            // Group is no longer suppressed or overridden.
+            // We should check if we need to transfer the alert back to the summary.
+            if (groupAlertEntry.mAlertSummaryOnNextAddition) {
+                if (!mHeadsUpManager.isAlerting(group.summary.getKey())) {
+                    alertNotificationWhenPossible(group.summary);
+                }
+                groupAlertEntry.mAlertSummaryOnNextAddition = false;
+            } else {
+                checkShouldTransferBack(groupAlertEntry);
+            }
+        }
     }
 
-    private void onAlertStateChanged(NotificationEntry entry, boolean isAlerting,
-            AlertingNotificationManager alertManager) {
-        if (isAlerting && mGroupManager.isSummaryOfSuppressedGroup(entry.getSbn())) {
-            handleSuppressedSummaryAlerted(entry, alertManager);
+    @Override
+    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
+        if (DEBUG) {
+            Log.d(TAG, "!! onHeadsUpStateChanged: entry=" + entry + " isHeadsUp=" + isHeadsUp);
+        }
+        if (isHeadsUp && entry.getSbn().getNotification().isGroupSummary()) {
+            // a group summary is alerting; trigger the forward transfer checks
+            checkForForwardAlertTransfer(entry, /* oldAlertOverride */ null);
+        }
+    }
+
+    /**
+     * Handles changes in a group's suppression or alertOverride, but where at least one of those
+     * conditions is still true (either the group is suppressed, the group has an alertOverride,
+     * or both).  The method determined which kind of child needs to receive the alert, finds the
+     * entry currently alerting, and makes the transfer.
+     *
+     * Internally, this is handled with two main cases: the override needs the alert, or there is
+     * no override but the summary is suppressed (so an isolated child needs the alert).
+     *
+     * @param summary the notification entry of the summary of the logical group.
+     * @param oldAlertOverride the former value of group.alertOverride, before whatever event
+     *                         required us to check for for a transfer condition.
+     */
+    private void checkForForwardAlertTransfer(NotificationEntry summary,
+            NotificationEntry oldAlertOverride) {
+        if (DEBUG) {
+            Log.d(TAG, "checkForForwardAlertTransfer: enter");
+        }
+        NotificationGroup group = mGroupManager.getGroupForSummary(summary.getSbn());
+        if (group != null && group.alertOverride != null) {
+            handleOverriddenSummaryAlerted(summary);
+        } else if (mGroupManager.isSummaryOfSuppressedGroup(summary.getSbn())) {
+            handleSuppressedSummaryAlerted(summary, oldAlertOverride);
         }
     }
 
@@ -186,9 +247,16 @@
         // see as early as we can if we need to abort a transfer.
         @Override
         public void onPendingEntryAdded(NotificationEntry entry) {
+            if (DEBUG) {
+                Log.d(TAG, "!! onPendingEntryAdded: entry=" + entry);
+            }
             String groupKey = mGroupManager.getGroupKey(entry.getSbn());
             GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
-            if (groupAlertEntry != null) {
+            if (groupAlertEntry != null && groupAlertEntry.mGroup.alertOverride == null) {
+                // new pending group entries require us to transfer back from the child to the
+                // group, but alertOverrides are only present in very limited circumstances, so
+                // while it's possible the group should ALSO alert, the previous detection which set
+                // this alertOverride won't be invalidated by this notification added to this group.
                 checkShouldTransferBack(groupAlertEntry);
             }
         }
@@ -262,43 +330,128 @@
     }
 
     /**
-     * Handles the scenario where a summary that has been suppressed is alerted.  A suppressed
+     * Handles the scenario where a summary that has been suppressed is itself, or has a former
+     * alertOverride (in the form of an isolated logical child) which was alerted.  A suppressed
      * summary should for all intents and purposes be invisible to the user and as a result should
      * not alert.  When this is the case, it is our responsibility to pass the alert to the
      * appropriate child which will be the representative notification alerting for the group.
      *
-     * @param summary the summary that is suppressed and alerting
-     * @param alertManager the alert manager that manages the alerting summary
+     * @param summary the summary that is suppressed and (potentially) alerting
+     * @param oldAlertOverride the alertOverride before whatever event triggered this method.  If
+     *                         the alert override was removed, this will be the entry that should
+     *                         be transferred back from.
      */
     private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary,
-            @NonNull AlertingNotificationManager alertManager) {
-        StatusBarNotification sbn = summary.getSbn();
+            NotificationEntry oldAlertOverride) {
+        if (DEBUG) {
+            Log.d(TAG, "handleSuppressedSummaryAlerted: summary=" + summary);
+        }
         GroupAlertEntry groupAlertEntry =
-                mGroupAlertEntries.get(mGroupManager.getGroupKey(sbn));
+                mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn()));
+
         if (!mGroupManager.isSummaryOfSuppressedGroup(summary.getSbn())
-                || !alertManager.isAlerting(sbn.getKey())
                 || groupAlertEntry == null) {
+            if (DEBUG) {
+                Log.d(TAG, "handleSuppressedSummaryAlerted: invalid state");
+            }
+            return;
+        }
+        boolean summaryIsAlerting = mHeadsUpManager.isAlerting(summary.getKey());
+        boolean priorityIsAlerting = oldAlertOverride != null
+                && mHeadsUpManager.isAlerting(oldAlertOverride.getKey());
+        if (!summaryIsAlerting && !priorityIsAlerting) {
+            if (DEBUG) {
+                Log.d(TAG, "handleSuppressedSummaryAlerted: no summary or override alerting");
+            }
             return;
         }
 
         if (pendingInflationsWillAddChildren(groupAlertEntry.mGroup)) {
             // New children will actually be added to this group, let's not transfer the alert.
+            if (DEBUG) {
+                Log.d(TAG, "handleSuppressedSummaryAlerted: pending inflations");
+            }
             return;
         }
 
         NotificationEntry child =
                 mGroupManager.getLogicalChildren(summary.getSbn()).iterator().next();
-        if (child != null) {
-            if (child.getRow().keepInParent()
-                    || child.isRowRemoved()
-                    || child.isRowDismissed()) {
-                // The notification is actually already removed. No need to alert it.
-                return;
+        if (summaryIsAlerting) {
+            if (DEBUG) {
+                Log.d(TAG, "handleSuppressedSummaryAlerted: transfer summary -> child");
             }
-            if (!alertManager.isAlerting(child.getKey()) && onlySummaryAlerts(summary)) {
-                groupAlertEntry.mLastAlertTransferTime = SystemClock.elapsedRealtime();
+            tryTransferAlertState(summary, /*from*/ summary, /*to*/ child, groupAlertEntry);
+            return;
+        }
+        // Summary didn't have the alert, so we're in "transfer back" territory.  First, make sure
+        // it's not too late to transfer back, then transfer the alert from the oldAlertOverride to
+        // the isolated child which should receive the alert.
+        if (!canStillTransferBack(groupAlertEntry)) {
+            if (DEBUG) {
+                Log.d(TAG, "handleSuppressedSummaryAlerted: transfer from override: too late");
             }
-            transferAlertState(summary, child, alertManager);
+            return;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "handleSuppressedSummaryAlerted: transfer override -> child");
+        }
+        tryTransferAlertState(summary, /*from*/ oldAlertOverride, /*to*/ child, groupAlertEntry);
+    }
+
+    /**
+     * Checks for and handles the scenario where the given entry is the summary of a group which
+     * has an alertOverride, and either the summary itself or one of its logical isolated children
+     * is currently alerting (which happens if the summary is suppressed).
+     */
+    private void handleOverriddenSummaryAlerted(NotificationEntry summary) {
+        if (DEBUG) {
+            Log.d(TAG, "handleOverriddenSummaryAlerted: summary=" + summary);
+        }
+        GroupAlertEntry groupAlertEntry =
+                mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn()));
+        NotificationGroup group = mGroupManager.getGroupForSummary(summary.getSbn());
+        if (group == null || group.alertOverride == null || groupAlertEntry == null) {
+            if (DEBUG) {
+                Log.d(TAG, "handleOverriddenSummaryAlerted: invalid state");
+            }
+            return;
+        }
+        boolean summaryIsAlerting = mHeadsUpManager.isAlerting(summary.getKey());
+        if (summaryIsAlerting) {
+            if (DEBUG) {
+                Log.d(TAG, "handleOverriddenSummaryAlerted: transfer summary -> override");
+            }
+            tryTransferAlertState(summary, /*from*/ summary, group.alertOverride, groupAlertEntry);
+            return;
+        }
+        // Summary didn't have the alert, so we're in "transfer back" territory.  First, make sure
+        // it's not too late to transfer back, then remove the alert from any of the logical
+        // children, and if one of them was alerting, we can alert the override.
+        if (!canStillTransferBack(groupAlertEntry)) {
+            if (DEBUG) {
+                Log.d(TAG, "handleOverriddenSummaryAlerted: transfer from child: too late");
+            }
+            return;
+        }
+        List<NotificationEntry> children = mGroupManager.getLogicalChildren(summary.getSbn());
+        if (children == null) {
+            if (DEBUG) {
+                Log.d(TAG, "handleOverriddenSummaryAlerted: no children");
+            }
+            return;
+        }
+        children.remove(group.alertOverride); // do not release the alert on our desired destination
+        boolean releasedChild = releaseChildAlerts(children);
+        if (releasedChild) {
+            if (DEBUG) {
+                Log.d(TAG, "handleOverriddenSummaryAlerted: transfer child -> override");
+            }
+            tryTransferAlertState(summary, /*from*/ null, group.alertOverride, groupAlertEntry);
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "handleOverriddenSummaryAlerted: no child alert released");
+            }
         }
     }
 
@@ -307,14 +460,37 @@
      * immediately to have the incorrect one up as short as possible. The second should alert
      * when possible.
      *
+     * @param summary entry of the summary
      * @param fromEntry entry to transfer alert from
      * @param toEntry entry to transfer to
-     * @param alertManager alert manager for the alert type
      */
-    private void transferAlertState(@NonNull NotificationEntry fromEntry, @NonNull NotificationEntry toEntry,
-            @NonNull AlertingNotificationManager alertManager) {
-        alertManager.removeNotification(fromEntry.getKey(), true /* releaseImmediately */);
-        alertNotificationWhenPossible(toEntry, alertManager);
+    private void tryTransferAlertState(
+            NotificationEntry summary,
+            NotificationEntry fromEntry,
+            NotificationEntry toEntry,
+            GroupAlertEntry groupAlertEntry) {
+        if (toEntry != null) {
+            if (toEntry.getRow().keepInParent()
+                    || toEntry.isRowRemoved()
+                    || toEntry.isRowDismissed()) {
+                // The notification is actually already removed. No need to alert it.
+                return;
+            }
+            if (!mHeadsUpManager.isAlerting(toEntry.getKey()) && onlySummaryAlerts(summary)) {
+                groupAlertEntry.mLastAlertTransferTime = SystemClock.elapsedRealtime();
+            }
+            if (DEBUG) {
+                Log.d(TAG, "transferAlertState: fromEntry=" + fromEntry + " toEntry=" + toEntry);
+            }
+            transferAlertState(fromEntry, toEntry);
+        }
+    }
+    private void transferAlertState(@Nullable NotificationEntry fromEntry,
+            @NonNull NotificationEntry toEntry) {
+        if (fromEntry != null) {
+            mHeadsUpManager.removeNotification(fromEntry.getKey(), true /* releaseImmediately */);
+        }
+        alertNotificationWhenPossible(toEntry);
     }
 
     /**
@@ -326,11 +502,13 @@
      * more children are coming. Thus, if a child is added within a certain timeframe after we
      * transfer, we back out and alert the summary again.
      *
+     * An alert can only transfer back within a small window of time after a transfer away from the
+     * summary to a child happened.
+     *
      * @param groupAlertEntry group alert entry to check
      */
     private void checkShouldTransferBack(@NonNull GroupAlertEntry groupAlertEntry) {
-        if (SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime
-                < ALERT_TRANSFER_TIMEOUT) {
+        if (canStillTransferBack(groupAlertEntry)) {
             NotificationEntry summary = groupAlertEntry.mGroup.summary;
 
             if (!onlySummaryAlerts(summary)) {
@@ -338,30 +516,17 @@
             }
             ArrayList<NotificationEntry> children = mGroupManager.getLogicalChildren(
                     summary.getSbn());
-            int numChildren = children.size();
+            int numActiveChildren = children.size();
             int numPendingChildren = getPendingChildrenNotAlerting(groupAlertEntry.mGroup);
-            numChildren += numPendingChildren;
+            int numChildren = numActiveChildren + numPendingChildren;
             if (numChildren <= 1) {
                 return;
             }
-            boolean releasedChild = false;
-            for (int i = 0; i < children.size(); i++) {
-                NotificationEntry entry = children.get(i);
-                if (onlySummaryAlerts(entry) && mHeadsUpManager.isAlerting(entry.getKey())) {
-                    releasedChild = true;
-                    mHeadsUpManager.removeNotification(
-                            entry.getKey(), true /* releaseImmediately */);
-                }
-                if (mPendingAlerts.containsKey(entry.getKey())) {
-                    // This is the child that would've been removed if it was inflated.
-                    releasedChild = true;
-                    mPendingAlerts.get(entry.getKey()).mAbortOnInflation = true;
-                }
-            }
+            boolean releasedChild = releaseChildAlerts(children);
             if (releasedChild && !mHeadsUpManager.isAlerting(summary.getKey())) {
-                boolean notifyImmediately = (numChildren - numPendingChildren) > 1;
+                boolean notifyImmediately = numActiveChildren > 1;
                 if (notifyImmediately) {
-                    alertNotificationWhenPossible(summary, mHeadsUpManager);
+                    alertNotificationWhenPossible(summary);
                 } else {
                     // Should wait until the pending child inflates before alerting.
                     groupAlertEntry.mAlertSummaryOnNextAddition = true;
@@ -371,25 +536,61 @@
         }
     }
 
+    private boolean canStillTransferBack(@NonNull GroupAlertEntry groupAlertEntry) {
+        return SystemClock.elapsedRealtime() - groupAlertEntry.mLastAlertTransferTime
+                < ALERT_TRANSFER_TIMEOUT;
+    }
+
+    private boolean releaseChildAlerts(List<NotificationEntry> children) {
+        boolean releasedChild = false;
+        if (SPEW) {
+            Log.d(TAG, "releaseChildAlerts: numChildren=" + children.size());
+        }
+        for (int i = 0; i < children.size(); i++) {
+            NotificationEntry entry = children.get(i);
+            if (SPEW) {
+                Log.d(TAG, "releaseChildAlerts: checking i=" + i + " entry=" + entry
+                        + " onlySummaryAlerts=" + onlySummaryAlerts(entry)
+                        + " isAlerting=" + mHeadsUpManager.isAlerting(entry.getKey())
+                        + " isPendingAlert=" + mPendingAlerts.containsKey(entry.getKey()));
+            }
+            if (onlySummaryAlerts(entry) && mHeadsUpManager.isAlerting(entry.getKey())) {
+                releasedChild = true;
+                mHeadsUpManager.removeNotification(
+                        entry.getKey(), true /* releaseImmediately */);
+            }
+            if (mPendingAlerts.containsKey(entry.getKey())) {
+                // This is the child that would've been removed if it was inflated.
+                releasedChild = true;
+                mPendingAlerts.get(entry.getKey()).mAbortOnInflation = true;
+            }
+        }
+        if (SPEW) {
+            Log.d(TAG, "releaseChildAlerts: didRelease=" + releasedChild);
+        }
+        return releasedChild;
+    }
+
     /**
      * Tries to alert the notification. If its content view is not inflated, we inflate and continue
      * when the entry finishes inflating the view.
      *
      * @param entry entry to show
-     * @param alertManager alert manager for the alert type
      */
-    private void alertNotificationWhenPossible(@NonNull NotificationEntry entry,
-            @NonNull AlertingNotificationManager alertManager) {
-        @InflationFlag int contentFlag = alertManager.getContentFlag();
+    private void alertNotificationWhenPossible(@NonNull NotificationEntry entry) {
+        @InflationFlag int contentFlag = mHeadsUpManager.getContentFlag();
         final RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
         if ((params.getContentViews() & contentFlag) == 0) {
+            if (DEBUG) {
+                Log.d(TAG, "alertNotificationWhenPossible: async requestRebind entry=" + entry);
+            }
             mPendingAlerts.put(entry.getKey(), new PendingAlertInfo(entry));
             params.requireContentViews(contentFlag);
             mRowContentBindStage.requestRebind(entry, en -> {
                 PendingAlertInfo alertInfo = mPendingAlerts.remove(entry.getKey());
                 if (alertInfo != null) {
                     if (alertInfo.isStillValid()) {
-                        alertNotificationWhenPossible(entry, mHeadsUpManager);
+                        alertNotificationWhenPossible(entry);
                     } else {
                         // The transfer is no longer valid. Free the content.
                         mRowContentBindStage.getStageParams(entry).markContentViewsFreeable(
@@ -400,10 +601,16 @@
             });
             return;
         }
-        if (alertManager.isAlerting(entry.getKey())) {
-            alertManager.updateNotification(entry.getKey(), true /* alert */);
+        if (mHeadsUpManager.isAlerting(entry.getKey())) {
+            if (DEBUG) {
+                Log.d(TAG, "alertNotificationWhenPossible: continue alerting entry=" + entry);
+            }
+            mHeadsUpManager.updateNotification(entry.getKey(), true /* alert */);
         } else {
-            alertManager.showNotification(entry);
+            if (DEBUG) {
+                Log.d(TAG, "alertNotificationWhenPossible: start alerting entry=" + entry);
+            }
+            mHeadsUpManager.showNotification(entry);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index c0d713b..16abd12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -122,6 +122,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -306,6 +307,7 @@
     private final QSDetailDisplayer mQSDetailDisplayer;
     private final FeatureFlags mFeatureFlags;
     private final ScrimController mScrimController;
+    private final PrivacyDotViewController mPrivacyDotViewController;
 
     // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
     // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
@@ -602,6 +604,7 @@
             FeatureFlags featureFlags,
             QuickAccessWalletClient quickAccessWalletClient,
             KeyguardMediaController keyguardMediaController,
+            PrivacyDotViewController privacyDotViewController,
             @Main Executor uiExecutor) {
         super(view, falsingManager, dozeLog, keyguardStateController,
                 (SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
@@ -610,6 +613,7 @@
         mView = view;
         mVibratorHelper = vibratorHelper;
         mKeyguardMediaController = keyguardMediaController;
+        mPrivacyDotViewController = privacyDotViewController;
         mMetricsLogger = metricsLogger;
         mActivityManager = activityManager;
         mConfigurationController = configurationController;
@@ -1895,6 +1899,7 @@
             mKeyguardBypassController.setQSExpanded(expanded);
             mStatusBarKeyguardViewManager.setQsExpanded(expanded);
             mLockIconViewController.setQsExpanded(expanded);
+            mPrivacyDotViewController.setQsExpanded(expanded);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 142cf21..ebf2465 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -97,13 +97,13 @@
         mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
 
         mIconController = iconController;
+        mCarrierConfigTracker = carrierConfigTracker;
         mNetworkController = Dependency.get(NetworkController.class);
         mSecurityController = Dependency.get(SecurityController.class);
 
         Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
         mNetworkController.addCallback(this);
         mSecurityController.addCallback(this);
-        mCarrierConfigTracker = carrierConfigTracker;
     }
 
     public void destroy() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index f45218d..07e9fed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -364,11 +364,11 @@
                 if (network.equals(mLastNetwork) && validated == lastValidated) {
                     // Should not rely on getTransportTypes() returning the same order of transport
                     // types. So sort the array before comparing.
-                    int[] newTypes = networkCapabilities.getTransportTypes();
+                    int[] newTypes = getProcessedTransportTypes(networkCapabilities);
                     Arrays.sort(newTypes);
 
                     int[] lastTypes = (mLastNetworkCapabilities != null)
-                            ? mLastNetworkCapabilities.getTransportTypes() : null;
+                            ? getProcessedTransportTypes(mLastNetworkCapabilities) : null;
                     if (lastTypes != null) Arrays.sort(lastTypes);
 
                     if (Arrays.equals(newTypes, lastTypes)) {
@@ -533,6 +533,21 @@
         return mPhone.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
     }
 
+    private int[] getProcessedTransportTypes(NetworkCapabilities networkCapabilities) {
+        int[] transportTypes = networkCapabilities.getTransportTypes();
+        for (int i = 0; i < transportTypes.length; i++) {
+            // For VCN over WiFi, the transportType is set to be TRANSPORT_CELLULAR in the
+            // NetworkCapabilities, but we need to convert it into TRANSPORT_WIFI in order to
+            // distinguish it from VCN over Cellular.
+            if (transportTypes[i] == NetworkCapabilities.TRANSPORT_CELLULAR
+                    && Utils.tryGetWifiInfoForVcn(networkCapabilities) != null) {
+                transportTypes[i] = NetworkCapabilities.TRANSPORT_WIFI;
+                break;
+            }
+        }
+        return transportTypes;
+    }
+
     private MobileSignalController getDataController() {
         int dataSubId = mSubDefaults.getActiveDataSubId();
         return getControllerWithSubId(dataSubId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index edec618..41b1dd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -23,6 +23,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
+import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ContrastColorUtil;
@@ -58,15 +59,6 @@
     /** Spacing to be applied between views. */
     private final int mSpacing;
 
-    /** Horizontal padding of smart reply buttons if all of them use only one line of text. */
-    private final int mSingleLineButtonPaddingHorizontal;
-
-    /** Horizontal padding of smart reply buttons if at least one of them uses two lines of text. */
-    private final int mDoubleLineButtonPaddingHorizontal;
-
-    /** Increase in width of a smart reply button as a result of using two lines instead of one. */
-    private final int mSingleToDoubleLineButtonWidthIncrease;
-
     private final BreakIterator mBreakIterator;
 
     private PriorityQueue<Button> mCandidateButtonQueueForSqueezing;
@@ -114,8 +106,6 @@
                 mDefaultBackgroundColor);
 
         int spacing = 0;
-        int singleLineButtonPaddingHorizontal = 0;
-        int doubleLineButtonPaddingHorizontal = 0;
         int strokeWidth = 0;
 
         final TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.SmartReplyView,
@@ -125,10 +115,6 @@
             int attr = arr.getIndex(i);
             if (attr == R.styleable.SmartReplyView_spacing) {
                 spacing = arr.getDimensionPixelSize(i, 0);
-            } else if (attr == R.styleable.SmartReplyView_singleLineButtonPaddingHorizontal) {
-                singleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
-            } else if (attr == R.styleable.SmartReplyView_doubleLineButtonPaddingHorizontal) {
-                doubleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
             } else if (attr == R.styleable.SmartReplyView_buttonStrokeWidth) {
                 strokeWidth = arr.getDimensionPixelSize(i, 0);
             }
@@ -137,10 +123,6 @@
 
         mStrokeWidth = strokeWidth;
         mSpacing = spacing;
-        mSingleLineButtonPaddingHorizontal = singleLineButtonPaddingHorizontal;
-        mDoubleLineButtonPaddingHorizontal = doubleLineButtonPaddingHorizontal;
-        mSingleToDoubleLineButtonWidthIncrease =
-                2 * (doubleLineButtonPaddingHorizontal - singleLineButtonPaddingHorizontal);
 
         mBreakIterator = BreakIterator.getLineInstance();
 
@@ -222,6 +204,12 @@
         return new LayoutParams(params.width, params.height);
     }
 
+    private void clearLayoutLineCount(View view) {
+        if (view instanceof TextView) {
+            ((TextView) view).nullLayouts();
+        }
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int targetWidth = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED
@@ -237,8 +225,7 @@
 
         SmartSuggestionMeasures accumulatedMeasures = new SmartSuggestionMeasures(
                 mPaddingLeft + mPaddingRight,
-                0 /* maxChildHeight */,
-                mSingleLineButtonPaddingHorizontal);
+                0 /* maxChildHeight */);
         int displayedChildCount = 0;
 
         // Set up a list of suggestions where actions come before replies. Note that the Buttons
@@ -268,8 +255,7 @@
                 continue;
             }
 
-            child.setPadding(accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingTop(),
-                    accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingBottom());
+            clearLayoutLineCount(child);
             child.measure(MEASURE_SPEC_ANY_LENGTH, heightMeasureSpec);
 
             coveredSuggestions.add(child);
@@ -299,18 +285,6 @@
             accumulatedMeasures.mMaxChildHeight =
                     Math.max(accumulatedMeasures.mMaxChildHeight, childHeight);
 
-            // Do we need to increase the number of lines in smart reply buttons to two?
-            final boolean increaseToTwoLines =
-                    (accumulatedMeasures.mButtonPaddingHorizontal
-                            == mSingleLineButtonPaddingHorizontal)
-                    && (lineCount == 2 || accumulatedMeasures.mMeasuredWidth > targetWidth);
-            if (increaseToTwoLines) {
-                accumulatedMeasures.mMeasuredWidth +=
-                        (displayedChildCount + 1) * mSingleToDoubleLineButtonWidthIncrease;
-                accumulatedMeasures.mButtonPaddingHorizontal =
-                        mDoubleLineButtonPaddingHorizontal;
-            }
-
             // If the last button doesn't fit into the remaining width, try squeezing preceding
             // smart reply buttons.
             if (accumulatedMeasures.mMeasuredWidth > targetWidth) {
@@ -372,18 +346,11 @@
         mCandidateButtonQueueForSqueezing.clear();
 
         // Finally, we need to re-measure some buttons.
-        remeasureButtonsIfNecessary(accumulatedMeasures.mButtonPaddingHorizontal,
-                                    accumulatedMeasures.mMaxChildHeight);
+        remeasureButtonsIfNecessary(accumulatedMeasures.mMaxChildHeight);
 
         int buttonHeight = Math.max(getSuggestedMinimumHeight(), mPaddingTop
                 + accumulatedMeasures.mMaxChildHeight + mPaddingBottom);
 
-        // Set the corner radius to half the button height to make the side of the buttons look like
-        // a semicircle.
-        for (View smartSuggestionButton : smartSuggestions) {
-            setCornerRadius((Button) smartSuggestionButton, ((float) buttonHeight) / 2);
-        }
-
         setMeasuredDimension(
                 resolveSize(Math.max(getSuggestedMinimumWidth(),
                                      accumulatedMeasures.mMeasuredWidth),
@@ -411,18 +378,14 @@
     private static class SmartSuggestionMeasures {
         int mMeasuredWidth = -1;
         int mMaxChildHeight = -1;
-        int mButtonPaddingHorizontal = -1;
 
-        SmartSuggestionMeasures(int measuredWidth, int maxChildHeight,
-                int buttonPaddingHorizontal) {
+        SmartSuggestionMeasures(int measuredWidth, int maxChildHeight) {
             this.mMeasuredWidth = measuredWidth;
             this.mMaxChildHeight = maxChildHeight;
-            this.mButtonPaddingHorizontal = buttonPaddingHorizontal;
         }
 
         public SmartSuggestionMeasures clone() {
-            return new SmartSuggestionMeasures(
-                    mMeasuredWidth, mMaxChildHeight, mButtonPaddingHorizontal);
+            return new SmartSuggestionMeasures(mMeasuredWidth, mMaxChildHeight);
         }
     }
 
@@ -553,17 +516,11 @@
 
     private int squeezeButtonToTextWidth(Button button, int heightMeasureSpec, int textWidth) {
         int oldWidth = button.getMeasuredWidth();
-        if (button.getPaddingLeft() != mDoubleLineButtonPaddingHorizontal) {
-            // Correct for the fact that the button was laid out with single-line horizontal
-            // padding.
-            oldWidth += mSingleToDoubleLineButtonWidthIncrease;
-        }
 
         // Re-measure the squeezed smart reply button.
-        button.setPadding(mDoubleLineButtonPaddingHorizontal, button.getPaddingTop(),
-                mDoubleLineButtonPaddingHorizontal, button.getPaddingBottom());
+        clearLayoutLineCount(button);
         final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                2 * mDoubleLineButtonPaddingHorizontal + textWidth
+                button.getPaddingLeft() + button.getPaddingRight() + textWidth
                       + getLeftCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
         button.measure(widthMeasureSpec, heightMeasureSpec);
 
@@ -579,8 +536,7 @@
         }
     }
 
-    private void remeasureButtonsIfNecessary(
-            int buttonPaddingHorizontal, int maxChildHeight) {
+    private void remeasureButtonsIfNecessary(int maxChildHeight) {
         final int maxChildHeightMeasure =
                 MeasureSpec.makeMeasureSpec(maxChildHeight, MeasureSpec.EXACTLY);
 
@@ -602,24 +558,7 @@
                 newWidth = Integer.MAX_VALUE;
             }
 
-            // Re-measure reason 2: The button's horizontal padding is incorrect (because it was
-            // measured with the wrong number of lines).
-            if (child.getPaddingLeft() != buttonPaddingHorizontal) {
-                requiresNewMeasure = true;
-                if (newWidth != Integer.MAX_VALUE) {
-                    if (buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal) {
-                        // Change padding (2->1 line).
-                        newWidth -= mSingleToDoubleLineButtonWidthIncrease;
-                    } else {
-                        // Change padding (1->2 lines).
-                        newWidth += mSingleToDoubleLineButtonWidthIncrease;
-                    }
-                }
-                child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
-                        buttonPaddingHorizontal, child.getPaddingBottom());
-            }
-
-            // Re-measure reason 3: The button's height is less than the max height of all buttons
+            // Re-measure reason 2: The button's height is less than the max height of all buttons
             // (all should have the same height).
             if (child.getMeasuredHeight() != maxChildHeight) {
                 requiresNewMeasure = true;
@@ -725,23 +664,6 @@
         button.setTextColor(mCurrentTextColor);
     }
 
-    private void setCornerRadius(Button button, float radius) {
-        Drawable drawable = button.getBackground();
-        if (drawable instanceof RippleDrawable) {
-            // Mutate in case other notifications are using this drawable.
-            drawable = drawable.mutate();
-            RippleDrawable ripple = (RippleDrawable) drawable;
-            Drawable inset = ripple.getDrawable(0);
-            if (inset instanceof InsetDrawable) {
-                Drawable background = ((InsetDrawable) inset).getDrawable();
-                if (background instanceof GradientDrawable) {
-                    GradientDrawable gradientDrawable = (GradientDrawable) background;
-                    gradientDrawable.setCornerRadius(radius);
-                }
-            }
-        }
-    }
-
     enum SmartButtonType {
         REPLY,
         ACTION
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/DotIndicatorDecoration.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/DotIndicatorDecoration.java
index 644addf..5e9bae9 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/DotIndicatorDecoration.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/DotIndicatorDecoration.java
@@ -20,13 +20,10 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.text.TextPaint;
 import android.util.MathUtils;
 import android.view.View;
-import android.widget.TextView;
 
 import androidx.annotation.ColorInt;
-import androidx.core.content.ContextCompat;
 import androidx.core.graphics.ColorUtils;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -39,12 +36,10 @@
     @ColorInt private final int mUnselectedColor;
     @ColorInt private final int mSelectedColor;
     private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-    private final TextPaint mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
     private WalletCardCarousel mCardCarousel;
 
     DotIndicatorDecoration(Context context) {
         super();
-
         mUnselectedRadius =
                 context.getResources().getDimensionPixelSize(
                         R.dimen.card_carousel_dot_unselected_radius);
@@ -53,13 +48,8 @@
                         R.dimen.card_carousel_dot_selected_radius);
         mDotMargin = context.getResources().getDimensionPixelSize(R.dimen.card_carousel_dot_margin);
 
-        TextView textView = new TextView(context);
-        mTextPaint.set(textView.getPaint());
-        // Text color is not copied from text appearance.
-        mTextPaint.setColor(ContextCompat.getColor(context, R.color.GM2_blue_600));
-
-        mUnselectedColor = ContextCompat.getColor(context, R.color.GM2_grey_300);
-        mSelectedColor = ContextCompat.getColor(context, R.color.GM2_blue_600);
+        mUnselectedColor = context.getColor(com.android.internal.R.color.system_neutral1_300);
+        mSelectedColor = context.getColor(com.android.internal.R.color.system_neutral1_0);
     }
 
     @Override
@@ -107,9 +97,9 @@
             int i = isLayoutLtr() ? itemsDrawn : itemCount - itemsDrawn - 1;
 
             if (isSelectedItem(i)) {
-                drawSelectedDot(canvas, interpolatedProgress, i);
+                drawSelectedDot(canvas, interpolatedProgress);
             } else if (isNextItemInScrollingDirection(i)) {
-                drawFadingUnselectedDot(canvas, interpolatedProgress, i);
+                drawFadingUnselectedDot(canvas, interpolatedProgress);
             } else {
                 drawUnselectedDot(canvas);
             }
@@ -121,7 +111,7 @@
         this.mCardCarousel = null; // No need to hold a reference.
     }
 
-    private void drawSelectedDot(Canvas canvas, float progress, int position) {
+    private void drawSelectedDot(Canvas canvas, float progress) {
         // Divide progress by 2 because the other half of the animation is done by
         // drawFadingUnselectedDot.
         mPaint.setColor(
@@ -132,13 +122,13 @@
         canvas.translate(radius * 2, 0);
     }
 
-    private void drawFadingUnselectedDot(Canvas canvas, float progress, int position) {
+    private void drawFadingUnselectedDot(Canvas canvas, float progress) {
         // Divide progress by 2 because the first half of the animation is done by drawSelectedDot.
         int blendedColor =
                 ColorUtils.blendARGB(
                         mUnselectedColor, mSelectedColor, progress / 2);
         mPaint.setColor(getTransitionAdjustedColor(blendedColor));
-        float radius = MathUtils.lerp(mSelectedRadius, mUnselectedRadius, progress / 2);
+        float radius = MathUtils.lerp(mUnselectedRadius, mSelectedColor, progress / 2);
         canvas.drawCircle(radius, 0, radius, mPaint);
         canvas.translate(radius * 2, 0);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index ac8b16a..66bd48b 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -17,6 +17,7 @@
 package com.android.systemui.wallet.ui;
 
 import android.graphics.Color;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.service.quickaccesswallet.QuickAccessWalletClient;
@@ -95,7 +96,7 @@
         }
         setTitle("");
         getActionBar().setDisplayHomeAsUpEnabled(true);
-        getActionBar().setHomeAsUpIndicator(R.drawable.ic_close);
+        getActionBar().setHomeAsUpIndicator(getHomeIndicatorDrawable());
         getActionBar().setHomeActionContentDescription(R.string.accessibility_desc_close);
         WalletView walletView = requireViewById(R.id.wallet_view);
         mWalletScreenController = new WalletScreenController(
@@ -175,4 +176,10 @@
         mWalletScreenController.onDismissed();
         super.onDestroy();
     }
+
+    private Drawable getHomeIndicatorDrawable() {
+        Drawable drawable = getDrawable(R.drawable.ic_close);
+        drawable.setTint(getColor(com.android.internal.R.color.system_neutral1_300));
+        return drawable;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index c547bb3..dbb99d3 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -37,6 +37,7 @@
 import android.widget.TextView;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
 
 import java.util.List;
@@ -100,7 +101,7 @@
     public void onCardScroll(WalletCardViewInfo centerCard, WalletCardViewInfo nextCard,
             float percentDistanceFromCenter) {
         CharSequence centerCardText = getLabelText(centerCard);
-        Drawable centerCardIcon = centerCard.getIcon();
+        Drawable centerCardIcon = getHeaderIcon(mContext, centerCard);
         if (!TextUtils.equals(mCenterCardText, centerCardText)) {
             mCenterCardText = centerCardText;
             mCardLabel.setText(centerCardText);
@@ -221,11 +222,27 @@
     }
 
     private void renderHeaderIconAndActionButton(WalletCardViewInfo walletCard, boolean isLocked) {
-        mIcon.setImageDrawable(walletCard.getIcon());
-        mIcon.setVisibility(VISIBLE);
+        Drawable icon = getHeaderIcon(mContext, walletCard);
+        if (icon != null) {
+            mIcon.setImageDrawable(walletCard.getIcon());
+            mIcon.setVisibility(VISIBLE);
+        } else {
+            mIcon.setVisibility(INVISIBLE);
+        }
         renderActionButton(walletCard, isLocked);
     }
 
+    @Nullable
+    private static Drawable getHeaderIcon(Context context, WalletCardViewInfo walletCard) {
+        Drawable icon = walletCard.getIcon();
+        if (icon != null) {
+            icon.setTint(
+                    Utils.getColorAttrDefaultColor(
+                            context, com.android.internal.R.attr.colorAccentPrimary));
+        }
+        return icon;
+    }
+
     private void renderActionButton(WalletCardViewInfo walletCard, boolean isDeviceLocked) {
         CharSequence actionButtonText = getActionButtonText(walletCard);
         if (isDeviceLocked) {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 26b68af..6c30674 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -280,8 +280,8 @@
 
     @WMSingleton
     @Provides
-    static PipSurfaceTransactionHelper providePipSurfaceTransactionHelper(Context context) {
-        return new PipSurfaceTransactionHelper(context);
+    static PipSurfaceTransactionHelper providePipSurfaceTransactionHelper() {
+        return new PipSurfaceTransactionHelper();
     }
 
     @WMSingleton
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index 1d9eaae..77286b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -37,7 +37,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.statusbar.CommandQueue;
 
 import org.junit.Before;
@@ -67,9 +68,12 @@
     @Mock
     private ModeSwitchesController mModeSwitchesController;
     @Mock
-    private NavigationModeController mNavigationModeController;
+    private SysUiState mSysUiState;
     @Mock
     private IRemoteMagnificationAnimationCallback mAnimationCallback;
+    @Mock
+    private OverviewProxyService mOverviewProxyService;
+
     private IWindowMagnificationConnection mIWindowMagnificationConnection;
     private WindowMagnification mWindowMagnification;
 
@@ -83,8 +87,8 @@
         }).when(mAccessibilityManager).setWindowMagnificationConnection(
                 any(IWindowMagnificationConnection.class));
         mWindowMagnification = new WindowMagnification(getContext(),
-                getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController,
-                mNavigationModeController);
+                getContext().getMainThreadHandler(), mCommandQueue,
+                mModeSwitchesController, mSysUiState, mOverviewProxyService);
         mWindowMagnification.mAnimationControllerSupplier = new FakeAnimationControllerSupplier(
                 mContext.getSystemService(DisplayManager.class));
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index 4e4c33a..045fb57f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -41,6 +41,7 @@
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.model.SysUiState;
 
 import org.junit.After;
 import org.junit.Before;
@@ -83,6 +84,8 @@
     IRemoteMagnificationAnimationCallback mAnimationCallback;
     @Mock
     IRemoteMagnificationAnimationCallback mAnimationCallback2;
+    @Mock
+    SysUiState mSysUiState;
     private SpyWindowMagnificationController mController;
     private WindowMagnificationController mSpyController;
     private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
@@ -98,7 +101,7 @@
         mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2;
         mController = new SpyWindowMagnificationController(mContext, mHandler,
                 mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(),
-                mWindowMagnifierCallback);
+                mWindowMagnifierCallback, mSysUiState);
         mSpyController = mController.getSpyController();
         mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
                 mContext, mController, newValueAnimator());
@@ -394,6 +397,13 @@
         verify(mSpyController).onConfigurationChanged(100);
     }
 
+    @Test
+    public void updateSysUiStateFlag_passThrough() {
+        mWindowMagnificationAnimationController.updateSysUiStateFlag();
+
+        verify(mSpyController).updateSysUIStateFlag();
+    }
+
     private void verifyFinalSpec(float expectedScale, float expectedCenterX,
             float expectedCenterY) {
         assertEquals(expectedScale, mController.getScale(), 0f);
@@ -440,9 +450,9 @@
         SpyWindowMagnificationController(Context context, Handler handler,
                 SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
                 MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
-                WindowMagnifierCallback callback) {
+                WindowMagnifierCallback callback, SysUiState sysUiState) {
             super(context, handler, sfVsyncFrameProvider, mirrorWindowControl, transaction,
-                    callback);
+                    callback, sysUiState);
             mSpyController = Mockito.mock(WindowMagnificationController.class);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 7d617db..b8734df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -17,12 +17,15 @@
 package com.android.systemui.accessibility;
 
 import static android.view.Choreographer.FrameCallback;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+import static android.view.WindowInsets.Type.systemGestures;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
+
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.hasItems;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
@@ -33,6 +36,9 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -40,49 +46,60 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableResources;
+import android.text.TextUtils;
 import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
 import android.view.WindowManager;
+import android.view.WindowMetrics;
 import android.view.accessibility.AccessibilityNodeInfo;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.LargeTest;
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.util.leak.ReferenceTestUtils;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Answers;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-@SmallTest
+@LargeTest
 @RunWith(AndroidTestingRunner.class)
 public class WindowMagnificationControllerTest extends SysuiTestCase {
 
+    private static final int LAYOUT_CHANGE_TIMEOUT_MS = 5000;
     @Mock
-    Handler mHandler;
+    private Handler mHandler;
     @Mock
-    SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
+    private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
     @Mock
-    MirrorWindowControl mMirrorWindowControl;
+    private MirrorWindowControl mMirrorWindowControl;
     @Mock
-    WindowMagnifierCallback mWindowMagnifierCallback;
-    @Mock
-    SurfaceControl.Transaction mTransaction;
-    @Mock
+    private WindowMagnifierCallback mWindowMagnifierCallback;
+    @Mock (answer = Answers.RETURNS_DEEP_STUBS)
+    private SurfaceControl.Transaction mTransaction;
     private WindowManager mWindowManager;
+    private SysUiState mSysUiState = new SysUiState();
     private Resources mResources;
     private WindowMagnificationController mWindowMagnificationController;
     private Instrumentation mInstrumentation;
@@ -93,37 +110,30 @@
         MockitoAnnotations.initMocks(this);
         mContext = Mockito.spy(getContext());
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
-        WindowManager wm = mContext.getSystemService(WindowManager.class);
-        doAnswer(invocation ->
-                wm.getMaximumWindowMetrics()
-        ).when(mWindowManager).getMaximumWindowMetrics();
-        doAnswer(invocation ->
-                wm.getCurrentWindowMetrics()
-        ).when(mWindowManager).getCurrentWindowMetrics();
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        mWindowManager = spy(new TestableWindowManager(wm));
+
         mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
         doAnswer(invocation -> {
-            mMirrorView = invocation.getArgument(0);
-            WindowManager.LayoutParams lp = invocation.getArgument(1);
-            mMirrorView.setLayoutParams(lp);
-            return null;
-        }).when(mWindowManager).addView(any(View.class), any(WindowManager.LayoutParams.class));
-        doAnswer(invocation -> {
-            mMirrorView = null;
-            return null;
-        }).when(mWindowManager).removeView(any(View.class));
-        doAnswer(invocation -> {
             FrameCallback callback = invocation.getArgument(0);
             callback.doFrame(0);
             return null;
         }).when(mSfVsyncFrameProvider).postFrameCallback(
                 any(FrameCallback.class));
-        when(mTransaction.remove(any())).thenReturn(mTransaction);
-        when(mTransaction.setGeometry(any(), any(), any(),
-                anyInt())).thenReturn(mTransaction);
+        doAnswer(invocation -> {
+            final Runnable runnable = invocation.getArgument(0);
+            runnable.run();
+            return null;
+        }).when(mHandler).post(
+                any(Runnable.class));
+
+        mSysUiState.addCallback(Mockito.mock(SysUiState.SysUiStateCallback.class));
+
         mResources = getContext().getOrCreateTestableResources().getResources();
         mWindowMagnificationController = new WindowMagnificationController(mContext,
                 mHandler, mSfVsyncFrameProvider,
-                mMirrorWindowControl, mTransaction, mWindowMagnifierCallback);
+                mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState);
+
         verify(mMirrorWindowControl).setWindowDelegate(
                 any(MirrorWindowControl.MirrorWindowDelegate.class));
     }
@@ -135,12 +145,21 @@
     }
 
     @Test
-    public void enableWindowMagnification_showControl() {
+    public void enableWindowMagnification_showControlAndNotifyBoundsChanged() {
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                     Float.NaN);
         });
+
         verify(mMirrorWindowControl).showControl();
+        ArgumentCaptor<Rect> boundsCaptor = ArgumentCaptor.forClass(Rect.class);
+        verify(mWindowMagnifierCallback,
+                timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onWindowMagnifierBoundsChanged(
+                eq(mContext.getDisplayId()), boundsCaptor.capture());
+        final Rect actualBounds = new Rect();
+        mMirrorView.getBoundsOnScreen(actualBounds);
+        assertEquals(actualBounds, boundsCaptor.getValue());
+
     }
 
     @Test
@@ -158,6 +177,25 @@
     }
 
     @Test
+    public void deleteWindowMagnification_enableAtTheBottom_overlapFlagIsFalse() {
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                    bounds.bottom);
+        });
+        ReferenceTestUtils.waitForCondition(this::hasMagnificationOverlapFlag);
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.deleteWindowMagnification();
+        });
+
+        verify(mMirrorWindowControl).destroyControl();
+        assertFalse(hasMagnificationOverlapFlag());
+    }
+
+    @Test
     public void moveMagnifier_schedulesFrame() {
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
@@ -210,7 +248,8 @@
         });
 
         assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
-        verify(mWindowManager).updateViewLayout(any(), any());
+        // The first invocation is called when the surface is created.
+        verify(mWindowManager, times(2)).updateViewLayout(any(), any());
     }
 
     @Test
@@ -318,17 +357,6 @@
     }
 
     @Test
-    public void onNavigationModeChanged_updateMirrorViewLayout() {
-        mInstrumentation.runOnMainSync(() -> {
-            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
-                    Float.NaN);
-            mWindowMagnificationController.onNavigationModeChanged(NAV_BAR_MODE_GESTURAL);
-        });
-
-        verify(mWindowManager).updateViewLayout(eq(mMirrorView), any());
-    }
-
-    @Test
     public void enableWindowMagnification_hasA11yWindowTitle() {
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
@@ -353,16 +381,12 @@
         final TestableResources testableResources = getContext().getOrCreateTestableResources();
         testableResources.addOverride(com.android.internal.R.string.android_system_label,
                 newA11yWindowTitle);
-        when(mContext.getResources()).thenReturn(testableResources.getResources());
 
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_LOCALE);
         });
 
-        ArgumentCaptor<WindowManager.LayoutParams> paramsArgumentCaptor = ArgumentCaptor.forClass(
-                WindowManager.LayoutParams.class);
-        verify(mWindowManager).updateViewLayout(eq(mMirrorView), paramsArgumentCaptor.capture());
-        assertEquals(newA11yWindowTitle, paramsArgumentCaptor.getValue().accessibilityTitle);
+        assertTrue(TextUtils.equals(newA11yWindowTitle, getAccessibilityWindowTitle()));
     }
 
     @Test
@@ -386,4 +410,95 @@
         }
         fail("mMirrorView scale is not changed");
     }
+
+    @Test
+    public void moveWindowMagnificationToTheBottom_enabled_overlapFlagIsTrue() {
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+                    Float.NaN);
+        });
+
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationController.moveWindowMagnifier(0, bounds.height());
+        });
+
+        ReferenceTestUtils.waitForCondition(() -> hasMagnificationOverlapFlag());
+    }
+
+    private CharSequence getAccessibilityWindowTitle() {
+        if (mMirrorView == null) {
+            return  null;
+        }
+        WindowManager.LayoutParams layoutParams =
+                (WindowManager.LayoutParams) mMirrorView.getLayoutParams();
+        return layoutParams.accessibilityTitle;
+    }
+
+    private boolean hasMagnificationOverlapFlag() {
+        return (mSysUiState.getFlags() & SYSUI_STATE_MAGNIFICATION_OVERLAP) != 0;
+    }
+
+    private class TestableWindowManager implements WindowManager {
+
+        private final WindowManager mWindowManager;
+
+        TestableWindowManager(WindowManager windowManager) {
+            mWindowManager = windowManager;
+        }
+
+        @Override
+        public Display getDefaultDisplay() {
+            return mWindowManager.getDefaultDisplay();
+        }
+
+        @Override
+        public void removeViewImmediate(View view) {
+            mWindowManager.removeViewImmediate(view);
+        }
+
+        @Override
+        public void requestAppKeyboardShortcuts(KeyboardShortcutsReceiver receiver, int deviceId) {
+            mWindowManager.requestAppKeyboardShortcuts(receiver, deviceId);
+        }
+
+        @Override
+        public Region getCurrentImeTouchRegion() {
+            return mWindowManager.getCurrentImeTouchRegion();
+        }
+
+        @Override
+        public void addView(View view, ViewGroup.LayoutParams params) {
+            mMirrorView = view;
+            mWindowManager.addView(view, params);
+        }
+
+        @Override
+        public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
+            mWindowManager.updateViewLayout(view, params);
+        }
+
+        @Override
+        public void removeView(View view) {
+            mMirrorView = null;
+            mWindowManager.removeView(view);
+        }
+
+        @Override
+        public WindowMetrics getCurrentWindowMetrics() {
+            final Insets systemGesturesInsets = Insets.of(0, 0, 0, 10);
+            final WindowInsets insets = new WindowInsets.Builder()
+                    .setInsets(systemGestures(), systemGesturesInsets)
+                    .build();
+            final WindowMetrics windowMetrics = new WindowMetrics(
+                    mWindowManager.getCurrentWindowMetrics().getBounds(), insets);
+            return windowMetrics;
+        }
+
+        @Override
+        public WindowMetrics getMaximumWindowMetrics() {
+            return mWindowManager.getMaximumWindowMetrics();
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 7833114..6ef7cc3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -16,15 +16,21 @@
 
 package com.android.systemui.accessibility;
 
+import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP;
+
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
 import android.os.RemoteException;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -36,12 +42,14 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.statusbar.CommandQueue;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -50,17 +58,21 @@
 @TestableLooper.RunWithLooper
 public class WindowMagnificationTest extends SysuiTestCase {
 
+    private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
     @Mock
     private AccessibilityManager mAccessibilityManager;
     @Mock
     private ModeSwitchesController mModeSwitchesController;
     @Mock
-    private NavigationModeController mNavigationModeController;
+    private SysUiState mSysUiState;
     @Mock
     private IWindowMagnificationConnectionCallback mConnectionCallback;
+    @Mock
+    private OverviewProxyService mOverviewProxyService;
+
     private CommandQueue mCommandQueue;
     private WindowMagnification mWindowMagnification;
-
+    private OverviewProxyListener mOverviewProxyListener;
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -72,11 +84,18 @@
         }).when(mAccessibilityManager).setWindowMagnificationConnection(
                 any(IWindowMagnificationConnection.class));
 
+        when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState);
+
         mCommandQueue = new CommandQueue(getContext());
         mWindowMagnification = new WindowMagnification(getContext(),
                 getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController,
-                mNavigationModeController);
+                mSysUiState, mOverviewProxyService);
         mWindowMagnification.start();
+
+        final ArgumentCaptor<OverviewProxyListener> listenerArgumentCaptor =
+                ArgumentCaptor.forClass(OverviewProxyListener.class);
+        verify(mOverviewProxyService).addCallback(listenerArgumentCaptor.capture());
+        mOverviewProxyListener = listenerArgumentCaptor.getValue();
     }
 
     @Test
@@ -99,10 +118,9 @@
         mCommandQueue.requestWindowMagnificationConnection(true);
         waitForIdleSync();
 
-        mWindowMagnification.onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY, testBounds);
+        mWindowMagnification.onWindowMagnifierBoundsChanged(TEST_DISPLAY, testBounds);
 
-        verify(mConnectionCallback).onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY,
-                testBounds);
+        verify(mConnectionCallback).onWindowMagnifierBoundsChanged(TEST_DISPLAY, testBounds);
     }
 
     @Test
@@ -111,10 +129,9 @@
         mCommandQueue.requestWindowMagnificationConnection(true);
         waitForIdleSync();
 
-        mWindowMagnification.onPerformScaleAction(Display.DEFAULT_DISPLAY, newScale);
+        mWindowMagnification.onPerformScaleAction(TEST_DISPLAY, newScale);
 
-        verify(mConnectionCallback).onPerformScaleAction(eq(Display.DEFAULT_DISPLAY),
-                eq(newScale));
+        verify(mConnectionCallback).onPerformScaleAction(TEST_DISPLAY, newScale);
     }
 
     @Test
@@ -122,9 +139,9 @@
         mCommandQueue.requestWindowMagnificationConnection(true);
         waitForIdleSync();
 
-        mWindowMagnification.onAccessibilityActionPerformed(Display.DEFAULT_DISPLAY);
+        mWindowMagnification.onAccessibilityActionPerformed(TEST_DISPLAY);
 
-        verify(mConnectionCallback).onAccessibilityActionPerformed(eq(Display.DEFAULT_DISPLAY));
+        verify(mConnectionCallback).onAccessibilityActionPerformed(TEST_DISPLAY);
     }
 
     @Test
@@ -135,4 +152,42 @@
 
         verify(mModeSwitchesController).onConfigurationChanged(anyInt());
     }
+
+    @Test
+    public void overviewProxyIsConnected_noController_resetFlag() {
+        mOverviewProxyListener.onConnectionChanged(true);
+
+        verify(mSysUiState).setFlag(SYSUI_STATE_MAGNIFICATION_OVERLAP, false);
+        verify(mSysUiState).commitUpdate(mContext.getDisplayId());
+    }
+
+    @Test
+    public void overviewProxyIsConnected_controllerIsAvailable_updateSysUiStateFlag() {
+        final WindowMagnificationAnimationController mController = mock(
+                WindowMagnificationAnimationController.class);
+        mWindowMagnification.mAnimationControllerSupplier = new FakeAnimationControllerSupplier(
+                mContext.getSystemService(DisplayManager.class), mController);
+        mWindowMagnification.mAnimationControllerSupplier.get(TEST_DISPLAY);
+
+        mOverviewProxyListener.onConnectionChanged(true);
+
+        verify(mController).updateSysUiStateFlag();
+    }
+
+    private static class FakeAnimationControllerSupplier extends
+            DisplayIdIndexSupplier<WindowMagnificationAnimationController> {
+
+        private final WindowMagnificationAnimationController mController;
+
+        FakeAnimationControllerSupplier(DisplayManager displayManager,
+                WindowMagnificationAnimationController controller) {
+            super(displayManager);
+            mController = controller;
+        }
+
+        @Override
+        protected WindowMagnificationAnimationController createInstance(Display display) {
+            return mController;
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpanTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpanTest.java
new file mode 100644
index 0000000..46c930f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpanTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.testing.AndroidTestingRunner;
+import android.text.SpannableStringBuilder;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/** Tests for {@link AnnotationLinkSpan}. */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class AnnotationLinkSpanTest extends SysuiTestCase {
+
+    private AnnotationLinkSpan.LinkInfo mLinkInfo;
+
+    @Before
+    public void setUp() {
+        mLinkInfo = new AnnotationLinkSpan.LinkInfo(
+                AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION,
+                mock(View.OnClickListener.class));
+    }
+
+    @Test
+    public void linkifyText_textAttachedWithSpan() {
+        final CharSequence text = getContext().getText(
+                R.string.accessibility_floating_button_migration_tooltip);
+        final SpannableStringBuilder builder =
+                (SpannableStringBuilder) AnnotationLinkSpan.linkify(text, mLinkInfo);
+        final int AnnotationLinkSpanNum =
+                builder.getSpans(/* queryStart= */ 0, builder.length(),
+                        AnnotationLinkSpan.class).length;
+
+        assertThat(AnnotationLinkSpanNum).isEqualTo(1);
+    }
+
+    @Test
+    public void linkifyText_withoutAnnotationTag_textWithoutSpan() {
+        final CharSequence text = "text without any annotation tag";
+        final SpannableStringBuilder builder =
+                (SpannableStringBuilder) AnnotationLinkSpan.linkify(text, mLinkInfo);
+        final int AnnotationLinkSpanNum =
+                builder.getSpans(/* queryStart= */ 0, builder.length(),
+                        AnnotationLinkSpan.class).length;
+
+        assertThat(AnnotationLinkSpanNum).isEqualTo(0);
+    }
+
+    @Test
+    public void linkifyText_twoLinkInfoWithSameAnnotation_listenerInvoked() {
+        final AtomicBoolean isClicked = new AtomicBoolean(false);
+        final CharSequence text = getContext().getText(
+                R.string.accessibility_floating_button_migration_tooltip);
+        final View.OnClickListener firstListener = v -> isClicked.set(true);
+        final AnnotationLinkSpan.LinkInfo firstLinkInfo = new AnnotationLinkSpan.LinkInfo(
+                AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION, firstListener);
+
+        final SpannableStringBuilder builder =
+                (SpannableStringBuilder) AnnotationLinkSpan.linkify(text, firstLinkInfo, mLinkInfo);
+        final AnnotationLinkSpan[] firstAnnotationLinkSpan =
+                builder.getSpans(/* queryStart= */ 0, builder.length(),
+                        AnnotationLinkSpan.class);
+        firstAnnotationLinkSpan[0].onClick(mock(View.class));
+
+        assertThat(isClicked.get()).isTrue();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipViewTest.java
new file mode 100644
index 0000000..6db5761
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipViewTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.MotionEventHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link BaseTooltipView}. */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class BaseTooltipViewTest extends SysuiTestCase {
+
+    @Mock
+    private WindowManager mWindowManager;
+
+    private AccessibilityFloatingMenuView mMenuView;
+    private BaseTooltipView mToolTipView;
+
+    private final MotionEventHelper mMotionEventHelper = new MotionEventHelper();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
+                mWindowManager).getMaximumWindowMetrics();
+        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
+
+        mMenuView = new AccessibilityFloatingMenuView(mContext);
+        mToolTipView = new BaseTooltipView(mContext, mMenuView);
+    }
+
+    @Test
+    public void showToolTipView_success() {
+        mToolTipView.show();
+
+        verify(mWindowManager).addView(eq(mToolTipView), any(WindowManager.LayoutParams.class));
+    }
+
+    @Test
+    public void touchOutsideWhenToolTipViewShown_dismiss() {
+        final MotionEvent outsideEvent =
+                mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0,
+                        /* eventTime= */1,
+                        MotionEvent.ACTION_OUTSIDE,
+                        /* x= */ 0,
+                        /* y= */ 0);
+
+        mToolTipView.show();
+        mToolTipView.dispatchTouchEvent(outsideEvent);
+
+        verify(mWindowManager).removeView(mToolTipView);
+    }
+
+    @Test
+    public void getAccessibilityActionList_matchResult() {
+        final AccessibilityNodeInfo infos = new AccessibilityNodeInfo();
+        mToolTipView.onInitializeAccessibilityNodeInfo(infos);
+
+        assertThat(infos.getActionList().size()).isEqualTo(1);
+    }
+
+    @Test
+    public void accessibilityAction_dismiss_success() {
+        final BaseTooltipView tooltipView =
+                spy(new BaseTooltipView(mContext, mMenuView));
+
+        final boolean isActionPerformed =
+                tooltipView.performAccessibilityAction(
+                        AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS.getId(),
+                        /* arguments= */ null);
+
+        assertThat(isActionPerformed).isTrue();
+        verify(tooltipView).hide();
+    }
+
+    @After
+    public void tearDown() {
+        mToolTipView.hide();
+        mMotionEventHelper.recycleEvents();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DockTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DockTooltipViewTest.java
new file mode 100644
index 0000000..41b948f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DockTooltipViewTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.MotionEventHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link DockTooltipView}. */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class DockTooltipViewTest extends SysuiTestCase {
+
+    @Mock
+    private WindowManager mWindowManager;
+
+    private AccessibilityFloatingMenuView mMenuView;
+    private DockTooltipView mDockTooltipView;
+    private final MotionEventHelper mMotionEventHelper = new MotionEventHelper();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
+                mWindowManager).getMaximumWindowMetrics();
+        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
+
+        mMenuView = spy(new AccessibilityFloatingMenuView(mContext));
+        mDockTooltipView = new DockTooltipView(mContext, mMenuView);
+    }
+
+    @Test
+    public void showTooltip_success() {
+        mDockTooltipView.show();
+
+        verify(mMenuView).startTranslateXAnimation();
+        verify(mWindowManager).addView(eq(mDockTooltipView), any(WindowManager.LayoutParams.class));
+    }
+
+    @Test
+    public void hideTooltip_success() {
+        mDockTooltipView.show();
+        mDockTooltipView.hide();
+
+        verify(mMenuView).stopTranslateXAnimation();
+        verify(mWindowManager).removeView(mDockTooltipView);
+    }
+
+    @Test
+    public void touchOutsideWhenToolTipViewShown_stopAnimation() {
+        final MotionEvent outsideEvent =
+                mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0,
+                        /* eventTime= */ 1,
+                        MotionEvent.ACTION_OUTSIDE,
+                        /* x= */ 0,
+                        /* y= */ 0);
+
+        mDockTooltipView.show();
+        mDockTooltipView.dispatchTouchEvent(outsideEvent);
+
+        verify(mMenuView).stopTranslateXAnimation();
+    }
+
+    @After
+    public void tearDown() {
+        mMotionEventHelper.recycleEvents();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipViewTest.java
new file mode 100644
index 0000000..c5bd2fe
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipViewTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.floatingmenu;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.text.SpannableString;
+import android.text.method.LinkMovementMethod;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for {@link MigrationTooltipView}. */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class MigrationTooltipViewTest extends SysuiTestCase {
+
+    private TextView mTextView;
+
+    @Before
+    public void setUp() {
+        final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext);
+        final MigrationTooltipView toolTipView = new MigrationTooltipView(mContext, menuView);
+        mTextView = toolTipView.findViewById(R.id.text);
+    }
+
+    @Test
+    public void onCreate_setLinkMovementMethod() {
+        assertThat(mTextView.getMovementMethod()).isInstanceOf(LinkMovementMethod.class);
+    }
+
+    @Test
+    public void onCreate_setDescription_matchTextAndSpanNum() {
+        final CharSequence expectedTextWithoutSpan =
+                AnnotationLinkSpan.linkify(mContext.getText(
+                R.string.accessibility_floating_button_migration_tooltip)).toString();
+        final SpannableString spannableString = (SpannableString) mTextView.getText();
+        final int AnnotationLinkSpanNum =
+                spannableString.getSpans(/* queryStart= */ 0, spannableString.length(),
+                        AnnotationLinkSpan.class).length;
+
+        assertThat(AnnotationLinkSpanNum).isEqualTo(1);
+        assertThat(mTextView.getText().toString().contentEquals(expectedTextWithoutSpan)).isTrue();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 875696a..46c1848 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -35,6 +35,7 @@
 import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.Vibrator;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.LayoutInflater;
@@ -69,6 +70,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -93,6 +95,8 @@
     @Mock
     private WindowManager mWindowManager;
     @Mock
+    private UdfpsHbmCallback mHbmCallback;
+    @Mock
     private StatusBarStateController mStatusBarStateController;
     @Mock
     private StatusBar mStatusBar;
@@ -114,6 +118,8 @@
     private AccessibilityManager mAccessibilityManager;
     @Mock
     private ScreenLifecycle mScreenLifecycle;
+    @Mock
+    private Vibrator mVibrator;
 
     private FakeExecutor mFgExecutor;
 
@@ -170,7 +176,9 @@
                 mFalsingManager,
                 mPowerManager,
                 mAccessibilityManager,
-                mScreenLifecycle);
+                mScreenLifecycle,
+                mVibrator,
+                Optional.of(mHbmCallback));
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
         verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -302,4 +310,29 @@
         // THEN no illumination because screen is off
         verify(mUdfpsView, never()).startIllumination(any());
     }
+
+    @Test
+    public void playHapticOnTouchUdfpsArea() throws RemoteException {
+        // Configure UdfpsView to accept the ACTION_DOWN event
+        when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+
+        // GIVEN that the overlay is showing
+        mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+                IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        // WHEN ACTION_DOWN is received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+        downEvent.recycle();
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        moveEvent.recycle();
+
+        // THEN click haptic is played
+        verify(mVibrator).vibrate(mUdfpsController.mEffectClick,
+                UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 80716f9..003368d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -39,6 +39,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.IWindowManager;
+import android.view.View;
 import android.view.WindowManagerPolicyConstants;
 
 import androidx.test.filters.SmallTest;
@@ -172,6 +173,44 @@
     }
 
     @Test
+    public void testShouldLogClose_backButton() {
+        mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+        doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+        doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+        doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+        GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
+        dialog.onBackPressed();
+        mTestableLooper.processAllMessages();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_BACK);
+    }
+
+    @Test
+    public void testShouldLogOnTapOutside() {
+        mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
+        doReturn(4).when(mGlobalActionsDialogLite).getMaxShownPowerItems();
+        doReturn(true).when(mGlobalActionsDialogLite).shouldDisplayLockdown(any());
+        doReturn(true).when(mGlobalActionsDialogLite).shouldShowAction(any());
+        String[] actions = {
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+                GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+        };
+        doReturn(actions).when(mGlobalActionsDialogLite).getDefaultActions();
+        GlobalActionsDialogLite.ActionsDialogLite dialog = mGlobalActionsDialogLite.createDialog();
+        View container = dialog.findViewById(com.android.systemui.R.id.global_actions_container);
+        container.callOnClick();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_CLOSE_TAP_OUTSIDE);
+    }
+
+    @Test
     public void testShouldLogBugreportPress() throws InterruptedException {
         GlobalActionsDialog.BugReportAction bugReportAction =
                 mGlobalActionsDialogLite.makeBugReportActionForTesting();
@@ -286,4 +325,44 @@
         assertThat(mGlobalActionsDialogLite.mOverflowItems).isEmpty();
         assertThat(mGlobalActionsDialogLite.mPowerItems).isEmpty();
     }
+
+    @Test
+    public void testShouldLogLockdownPress() {
+        GlobalActionsDialogLite.LockDownAction lockDownAction =
+                mGlobalActionsDialogLite.new LockDownAction();
+        lockDownAction.onPress();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_LOCKDOWN_PRESS);
+    }
+
+    @Test
+    public void testShouldLogShutdownPress() {
+        GlobalActionsDialogLite.ShutDownAction shutDownAction =
+                mGlobalActionsDialogLite.new ShutDownAction();
+        shutDownAction.onPress();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SHUTDOWN_PRESS);
+    }
+
+    @Test
+    public void testShouldLogShutdownLongPress() {
+        GlobalActionsDialogLite.ShutDownAction shutDownAction =
+                mGlobalActionsDialogLite.new ShutDownAction();
+        shutDownAction.onLongPress();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SHUTDOWN_LONG_PRESS);
+    }
+
+    @Test
+    public void testShouldLogRebootPress() {
+        GlobalActionsDialogLite.RestartAction restartAction =
+                mGlobalActionsDialogLite.new RestartAction();
+        restartAction.onPress();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_REBOOT_PRESS);
+    }
+
+    @Test
+    public void testShouldLogRebootLongPress() {
+        GlobalActionsDialogLite.RestartAction restartAction =
+                mGlobalActionsDialogLite.new RestartAction();
+        restartAction.onLongPress();
+        verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_REBOOT_LONG_PRESS);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 107ce28..d63c529 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -1041,7 +1041,6 @@
         Bundle newOptions = new Bundle();
         mManager.onAppWidgetOptionsChanged(SECOND_WIDGET_ID_WITH_SHORTCUT, newOptions);
 
-
         // Check that options is not modified
         verify(mAppWidgetManager, never()).updateAppWidgetOptions(
                 eq(SECOND_WIDGET_ID_WITH_SHORTCUT), any());
@@ -1478,6 +1477,8 @@
         widgetSp5.edit().clear().commit();
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
         sp.edit().clear().commit();
+        mManager.mListeners.clear();
+        mManager.mTiles.clear();
     }
 
     private void setStorageForTile(String shortcutId, String packageName, int widgetId,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index d35597f..6f7bf3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -35,6 +36,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.testing.FakeMetricsLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -82,6 +84,7 @@
     private QuickQSPanelController mQuickQSPanelController;
     private FakeTunerService mFakeTunerService;
     private MetricsLogger mMetricsLogger = new FakeMetricsLogger();
+    private FalsingManagerFake mFalsingManager;
 
     @Mock
     private SettingsButton mSettingsButton;
@@ -95,12 +98,15 @@
     private View mPowerMenuLiteView;
     @Mock
     private GlobalActionsDialogLite mGlobalActionsDialog;
+    @Mock
+    private UiEventLogger mUiEventLogger;
 
     private QSFooterViewController mController;
 
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
+        mFalsingManager = new FalsingManagerFake();
 
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
 
@@ -121,7 +127,8 @@
         mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
                 mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
                 mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService,
-                mMetricsLogger, new FalsingManagerFake(), false, mGlobalActionsDialog);
+                mMetricsLogger, mFalsingManager, false, mGlobalActionsDialog,
+                mUiEventLogger);
 
         mController.init();
     }
@@ -154,4 +161,27 @@
         // Verify Settings wasn't launched.
         verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
     }
+
+    @Test
+    public void testLogPowerMenuClick() {
+        // Enable power menu button
+        mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
+                mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
+                mMultiUserSwitchController, mQuickQSPanelController, mFakeTunerService,
+                mMetricsLogger, new FalsingManagerFake(), true, mGlobalActionsDialog,
+                mUiEventLogger);
+        mController.init();
+        mController.setExpanded(true);
+        mFalsingManager.setFalseTap(false);
+
+        ArgumentCaptor<View.OnClickListener> onClickCaptor =
+                ArgumentCaptor.forClass(View.OnClickListener.class);
+        verify(mPowerMenuLiteView).setOnClickListener(onClickCaptor.capture());
+
+        onClickCaptor.getValue().onClick(mPowerMenuLiteView);
+
+        // Verify clicks are logged
+        verify(mUiEventLogger, times(1))
+                .log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 234dec2..7caf0dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -21,6 +21,7 @@
 import static junit.framework.Assert.assertNotNull;
 
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -189,6 +190,29 @@
     }
 
     @Test
+    public void testUntappableView_profileOwnerOfOrgOwnedDevice() {
+        when(mSecurityController.isProfileOwnerOfOrganizationOwnedDevice()).thenReturn(true);
+
+        mFooter.refreshState();
+
+        TestableLooper.get(this).processAllMessages();
+        assertFalse(mRootView.isClickable());
+        assertEquals(View.GONE, mRootView.findViewById(R.id.footer_icon).getVisibility());
+    }
+
+    @Test
+    public void testTappableView_profileOwnerOfOrgOwnedDevice_networkLoggingEnabled() {
+        when(mSecurityController.isProfileOwnerOfOrganizationOwnedDevice()).thenReturn(true);
+        when(mSecurityController.isNetworkLoggingEnabled()).thenReturn(true);
+
+        mFooter.refreshState();
+
+        TestableLooper.get(this).processAllMessages();
+        assertTrue(mRootView.isClickable());
+        assertEquals(View.VISIBLE, mRootView.findViewById(R.id.footer_icon).getVisibility());
+    }
+
+    @Test
     public void testNetworkLoggingEnabled_deviceOwner() {
         when(mSecurityController.isDeviceManaged()).thenReturn(true);
         when(mSecurityController.isNetworkLoggingEnabled()).thenReturn(true);
@@ -435,10 +459,7 @@
     @Test
     public void testGetManagementMessage_noManagement() {
         assertEquals(null, mFooter.getManagementMessage(
-                /* isDeviceManaged= */ false,
-                MANAGING_ORGANIZATION,
-                /* isProfileOwnerOfOrganizationOwnedDevice= */ false,
-                MANAGING_ORGANIZATION));
+                /* isDeviceManaged= */ false, MANAGING_ORGANIZATION));
     }
 
     @Test
@@ -446,16 +467,11 @@
         assertEquals(mContext.getString(R.string.monitoring_description_named_management,
                                         MANAGING_ORGANIZATION),
                      mFooter.getManagementMessage(
-                             /* isDeviceManaged= */ true,
-                             MANAGING_ORGANIZATION,
-                             /* isProfileOwnerOfOrganizationOwnedDevice= */ false,
-                             /* workProfileOrganizationName= */ null));
+                             /* isDeviceManaged= */ true, MANAGING_ORGANIZATION));
         assertEquals(mContext.getString(R.string.monitoring_description_management),
                      mFooter.getManagementMessage(
                              /* isDeviceManaged= */ true,
-                             /* organizationName= */ null,
-                             /* isProfileOwnerOfOrganizationOwnedDevice= */ false,
-                             /* workProfileOrganizationName= */ null));
+                             /* organizationName= */ null));
     }
 
     @Test
@@ -467,27 +483,7 @@
         assertEquals(mContext.getString(R.string.monitoring_financed_description_named_management,
                 MANAGING_ORGANIZATION, MANAGING_ORGANIZATION),
                 mFooter.getManagementMessage(
-                        /* isDeviceManaged= */ true,
-                        MANAGING_ORGANIZATION,
-                        /* isProfileOwnerOfOrganizationOwnedDevice= */ false,
-                        /* workProfileOrganizationName= */ null));
-    }
-
-    @Test
-    public void testGetManagementMessage_profileOwnerOfOrganizationOwnedDevice() {
-        assertEquals(mContext.getString(R.string.monitoring_description_named_management,
-                MANAGING_ORGANIZATION),
-                mFooter.getManagementMessage(
-                        /* isDeviceManaged= */ false,
-                        /* organizationName= */ null,
-                        /* isProfileOwnerOfOrganizationOwnedDevice= */ true,
-                        MANAGING_ORGANIZATION));
-        assertEquals(mContext.getString(R.string.monitoring_description_management),
-                mFooter.getManagementMessage(
-                        /* isDeviceManaged= */ false,
-                        /* organizationName= */ null,
-                        /* isProfileOwnerOfOrganizationOwnedDevice= */ true,
-                        /* workProfileOrganizationName= */ null));
+                        /* isDeviceManaged= */ true, MANAGING_ORGANIZATION));
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
index e5e2e53..126dca5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
@@ -20,6 +20,7 @@
 import android.graphics.drawable.Drawable
 import android.service.quicksettings.Tile
 import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
 import android.text.TextUtils
 import android.view.View
 import androidx.test.filters.SmallTest
@@ -36,6 +37,7 @@
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 class QSTileViewImplTest : SysuiTestCase() {
 
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 7c8b413..88852f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -74,6 +74,7 @@
     private HeadsUpManager mHeadsUpManager;
     @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private RowContentBindStage mBindStage;
+    @Mock PeopleNotificationIdentifier mPeopleNotificationIdentifier;
     @Captor private ArgumentCaptor<NotificationEntryListener> mListenerCaptor;
     private NotificationEntryListener mNotificationEntryListener;
     private final HashMap<String, NotificationEntry> mPendingEntries = new HashMap<>();
@@ -91,7 +92,7 @@
 
         mGroupManager = new NotificationGroupManagerLegacy(
                 mock(StatusBarStateController.class),
-                () -> mock(PeopleNotificationIdentifier.class),
+                () -> mPeopleNotificationIdentifier,
                 Optional.of(mock(Bubbles.class)));
         mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager);
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
@@ -107,15 +108,31 @@
         mHeadsUpManager.addListener(mGroupAlertTransferHelper);
     }
 
+    private void mockHasHeadsUpContentView(NotificationEntry entry,
+            boolean hasHeadsUpContentView) {
+        RowContentBindParams params = new RowContentBindParams();
+        if (hasHeadsUpContentView) {
+            params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP);
+        }
+        when(mBindStage.getStageParams(eq(entry))).thenReturn(params);
+    }
+
+    private void mockHasHeadsUpContentView(NotificationEntry entry) {
+        mockHasHeadsUpContentView(entry, true);
+    }
+
+    private void mockIsPriority(NotificationEntry priorityEntry) {
+        when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry)))
+                .thenReturn(PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON);
+    }
+
     @Test
     public void testSuppressedSummaryHeadsUpTransfersToChild() {
         NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mHeadsUpManager.showNotification(summaryEntry);
         NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
 
-        RowContentBindParams params = new RowContentBindParams();
-        params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP);
-        when(mBindStage.getStageParams(eq(childEntry))).thenReturn(params);
+        mockHasHeadsUpContentView(childEntry);
 
         // Summary will be suppressed because there is only one child.
         mGroupManager.onEntryAdded(summaryEntry);
@@ -180,8 +197,7 @@
         NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mHeadsUpManager.showNotification(summaryEntry);
         NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        RowContentBindParams params = new RowContentBindParams();
-        when(mBindStage.getStageParams(eq(childEntry))).thenReturn(params);
+        mockHasHeadsUpContentView(childEntry, false);
 
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
@@ -198,8 +214,7 @@
         NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification();
         mHeadsUpManager.showNotification(summaryEntry);
         NotificationEntry childEntry = mGroupTestHelper.createChildNotification();
-        RowContentBindParams params = new RowContentBindParams();
-        when(mBindStage.getStageParams(eq(childEntry))).thenReturn(params);
+        mockHasHeadsUpContentView(childEntry, false);
 
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
@@ -250,8 +265,7 @@
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
         NotificationEntry childEntry =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        RowContentBindParams params = new RowContentBindParams();
-        when(mBindStage.getStageParams(eq(childEntry))).thenReturn(params);
+        mockHasHeadsUpContentView(childEntry, false);
 
         mHeadsUpManager.showNotification(summaryEntry);
         // Trigger a transfer of alert state from summary to child.
@@ -270,8 +284,7 @@
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
         NotificationEntry childEntry =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY);
-        RowContentBindParams params = new RowContentBindParams();
-        when(mBindStage.getStageParams(eq(childEntry))).thenReturn(params);
+        mockHasHeadsUpContentView(childEntry, false);
 
         mHeadsUpManager.showNotification(summaryEntry);
         // Trigger a transfer of alert state from summary to child.
@@ -294,8 +307,7 @@
                 mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
         NotificationEntry childEntry =
                 mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY, 47);
-        RowContentBindParams params = new RowContentBindParams();
-        when(mBindStage.getStageParams(eq(childEntry))).thenReturn(params);
+        mockHasHeadsUpContentView(childEntry, false);
 
         mHeadsUpManager.showNotification(summaryEntry);
         // Trigger a transfer of alert state from summary to child.
@@ -311,4 +323,160 @@
 
         assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
     }
+
+    @Test
+    public void testOverriddenSummaryHeadsUpTransfersToPriority() {
+        // Creation order is oldest to newest, meaning the priority will be deemed newest
+        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        mockIsPriority(priorityEntry);
+
+        // summary gets heads up
+        mHeadsUpManager.showNotification(summaryEntry);
+
+        mockHasHeadsUpContentView(summaryEntry);
+        mockHasHeadsUpContentView(priorityEntry);
+        mockHasHeadsUpContentView(childEntry);
+
+        // Summary will have an alertOverride.
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(priorityEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        // An overridden summary should transfer its alert state to the priority.
+        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
+        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
+        assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
+    }
+
+    @Test
+    public void testOverriddenSummaryHeadsUpTransferDoesNotAlertPriorityIfUninflated() {
+        // Creation order is oldest to newest, meaning the priority will be deemed newest
+        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        mockIsPriority(priorityEntry);
+
+        // summary gets heads up
+        mHeadsUpManager.showNotification(summaryEntry);
+
+        mockHasHeadsUpContentView(summaryEntry);
+        mockHasHeadsUpContentView(priorityEntry, false);
+        mockHasHeadsUpContentView(childEntry);
+
+        // Summary will have an alertOverride.
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(priorityEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        // Alert is immediately removed from summary, but we do not show priority yet either as its
+        // content is not inflated.
+        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
+        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
+        assertFalse(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
+        assertTrue(mGroupAlertTransferHelper.isAlertTransferPending(priorityEntry));
+    }
+
+    @Test
+    public void testOverriddenSummaryHeadsUpTransfersToPriorityButBackAgain() {
+        // Creation order is oldest to newest, meaning the child2 will ultimately be deemed newest
+        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        NotificationEntry childEntry2 = mGroupTestHelper.createChildNotification(groupAlert);
+        mockIsPriority(priorityEntry);
+
+        // summary gets heads up
+        mHeadsUpManager.showNotification(summaryEntry);
+
+        mockHasHeadsUpContentView(summaryEntry);
+        mockHasHeadsUpContentView(priorityEntry);
+        mockHasHeadsUpContentView(childEntry);
+        mockHasHeadsUpContentView(childEntry2);
+
+        // Summary will have an alertOverride.
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(priorityEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        // An overridden summary should transfer its alert state to the priority.
+        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
+        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
+        assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
+
+        mGroupManager.onEntryAdded(childEntry2);
+
+        // An overridden summary should transfer its alert state to the priority.
+        assertTrue(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
+        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
+        assertFalse(mHeadsUpManager.isAlerting(childEntry2.getKey()));
+        assertFalse(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
+    }
+
+    @Test
+    public void testOverriddenSuppressedSummaryHeadsUpTransfersToChildThenToPriority() {
+        // Creation order is oldest to newest, meaning the priority will ultimately be deemed newest
+        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        mockIsPriority(priorityEntry);
+
+        // summary gets heads up
+        mHeadsUpManager.showNotification(summaryEntry);
+
+        mockHasHeadsUpContentView(summaryEntry);
+        mockHasHeadsUpContentView(priorityEntry);
+        mockHasHeadsUpContentView(childEntry);
+
+        // Summary will be suppressed, and the child will receive the alert
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(childEntry);
+
+        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
+        assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey()));
+
+        // Alert should be transferred "back" from the child to the priority
+        mGroupManager.onEntryAdded(priorityEntry);
+
+        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
+        assertFalse(mHeadsUpManager.isAlerting(childEntry.getKey()));
+        assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
+    }
+
+    @Test
+    public void testOverriddenSuppressedSummaryHeadsUpTransfersToPriorityThenToChild() {
+        // Creation order is oldest to newest, meaning the child will ultimately be deemed newest
+        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
+        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        NotificationEntry childEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        mockIsPriority(priorityEntry);
+
+        // summary gets heads up
+        mHeadsUpManager.showNotification(summaryEntry);
+
+        mockHasHeadsUpContentView(summaryEntry);
+        mockHasHeadsUpContentView(priorityEntry);
+        mockHasHeadsUpContentView(childEntry);
+
+        // Summary will have alert override of the priority
+        mGroupManager.onEntryAdded(summaryEntry);
+        mGroupManager.onEntryAdded(priorityEntry);
+
+        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
+        assertTrue(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
+
+        // Alert should be transferred "back" from the priority to the child (which is newer)
+        mGroupManager.onEntryAdded(childEntry);
+
+        assertFalse(mHeadsUpManager.isAlerting(summaryEntry.getKey()));
+        assertTrue(mHeadsUpManager.isAlerting(childEntry.getKey()));
+        assertFalse(mHeadsUpManager.isAlerting(priorityEntry.getKey()));
+    }
+
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
index 3e9fd51..0110d7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
@@ -21,9 +21,12 @@
 import static junit.framework.Assert.assertTrue;
 
 import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Notification;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
@@ -33,6 +36,8 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.wm.shell.bubbles.Bubbles;
@@ -58,6 +63,7 @@
     private final NotificationGroupTestHelper mGroupTestHelper =
             new NotificationGroupTestHelper(mContext);
 
+    @Mock PeopleNotificationIdentifier mPeopleNotificationIdentifier;
     @Mock HeadsUpManager mHeadsUpManager;
 
     @Before
@@ -69,7 +75,7 @@
     private void initializeGroupManager() {
         mGroupManager = new NotificationGroupManagerLegacy(
                 mock(StatusBarStateController.class),
-                () -> mock(PeopleNotificationIdentifier.class),
+                () -> mPeopleNotificationIdentifier,
                 Optional.of(mock(Bubbles.class)));
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
     }
@@ -153,4 +159,72 @@
         assertEquals(childEntry, mGroupManager.getGroupSummary(childEntry));
         assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(childEntry));
     }
+
+    @Test
+    public void testAlertOverrideWithSiblings_0() {
+        helpTestAlertOverrideWithSiblings(0);
+    }
+
+    @Test
+    public void testAlertOverrideWithSiblings_1() {
+        helpTestAlertOverrideWithSiblings(1);
+    }
+
+    @Test
+    public void testAlertOverrideWithSiblings_2() {
+        helpTestAlertOverrideWithSiblings(2);
+    }
+
+    /**
+     * This tests, for a group with a priority entry and the given number of siblings, that:
+     * 1) the priority entry is identified as the alertOverride for the group
+     * 2) the onAlertOverrideChanged method is called at that time
+     * 3) when the priority entry is removed, these are reversed
+     */
+    private void helpTestAlertOverrideWithSiblings(int numSiblings) {
+        int groupAlert = Notification.GROUP_ALERT_SUMMARY;
+        // Create entries in an order so that the priority entry can be deemed the newest child.
+        NotificationEntry[] siblings = new NotificationEntry[numSiblings];
+        for (int i = 0; i < numSiblings; i++) {
+            siblings[i] = mGroupTestHelper.createChildNotification(groupAlert);
+        }
+        NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(groupAlert);
+        NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(groupAlert);
+
+        // The priority entry is an important conversation.
+        when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry)))
+                .thenReturn(PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON);
+
+        // Register a listener so we can verify that the event is sent.
+        OnGroupChangeListener groupChangeListener = mock(OnGroupChangeListener.class);
+        mGroupManager.registerGroupChangeListener(groupChangeListener);
+
+        // Add all the entries.  The order here shouldn't matter.
+        mGroupManager.onEntryAdded(summaryEntry);
+        for (int i = 0; i < numSiblings; i++) {
+            mGroupManager.onEntryAdded(siblings[i]);
+        }
+        mGroupManager.onEntryAdded(priorityEntry);
+
+        // Verify that the summary group has the priority child as its alertOverride
+        NotificationGroup summaryGroup = mGroupManager.getGroupForSummary(summaryEntry.getSbn());
+        assertEquals(priorityEntry, summaryGroup.alertOverride);
+        verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry);
+
+        // Verify that only the priority notification is isolated from the group
+        assertEquals(priorityEntry, mGroupManager.getGroupSummary(priorityEntry));
+        assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(priorityEntry));
+        // Verify that the siblings are NOT isolated from the group
+        for (int i = 0; i < numSiblings; i++) {
+            assertEquals(summaryEntry, mGroupManager.getGroupSummary(siblings[i]));
+            assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(siblings[i]));
+        }
+
+        // Remove the priority notification to validate that it is removed as the alertOverride
+        mGroupManager.onEntryRemoved(priorityEntry);
+
+        // verify that the alertOverride is removed when the priority notification is
+        assertNull(summaryGroup.alertOverride);
+        verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 4bac762..45761df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -89,6 +89,7 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.events.PrivacyDotViewController;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -243,6 +244,8 @@
     private QuickAccessWalletClient mQuickAccessWalletClient;
     @Mock
     private KeyguardMediaController mKeyguardMediaController;
+    @Mock
+    private PrivacyDotViewController mPrivacyDotViewController;
 
     private SysuiStatusBarStateController mStatusBarStateController;
     private NotificationPanelViewController mNotificationPanelViewController;
@@ -351,6 +354,7 @@
                 mFeatureFlags,
                 mQuickAccessWalletClient,
                 mKeyguardMediaController,
+                mPrivacyDotViewController,
                 new FakeExecutor(new FakeSystemClock()));
         mNotificationPanelViewController.initDependencies(
                 mStatusBar,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 3d07eb1..e5b7e3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -20,7 +20,6 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.never;
@@ -100,8 +99,6 @@
 
     private Icon mActionIcon;
 
-    private int mSingleLinePaddingHorizontal;
-    private int mDoubleLinePaddingHorizontal;
     private int mSpacing;
 
     private NotificationEntry mEntry;
@@ -141,10 +138,6 @@
         mView = SmartReplyView.inflate(mContext, mConstants);
 
         final Resources res = mContext.getResources();
-        mSingleLinePaddingHorizontal = res.getDimensionPixelSize(
-                R.dimen.smart_reply_button_padding_horizontal_single_line);
-        mDoubleLinePaddingHorizontal = res.getDimensionPixelSize(
-                R.dimen.smart_reply_button_padding_horizontal_double_line);
         mSpacing = res.getDimensionPixelSize(R.dimen.smart_reply_button_spacing);
 
         mNotification = new Notification.Builder(mContext, "")
@@ -588,18 +581,6 @@
         layout.setBaselineAligned(false);
 
         final boolean isRtl = mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-        final int paddingHorizontal;
-        switch (lineCount) {
-            case 1:
-                paddingHorizontal = mSingleLinePaddingHorizontal;
-                break;
-            case 2:
-                paddingHorizontal = mDoubleLinePaddingHorizontal;
-                break;
-            default:
-                fail("Invalid line count " + lineCount);
-                return null;
-        }
 
         // Add smart replies
         Button previous = null;
@@ -617,8 +598,6 @@
                                 true /* delayOnClickListener */))
                         .iterator()));
         for (Button current : inflatedReplies) {
-            current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal,
-                    current.getPaddingBottom());
             if (previous != null) {
                 ViewGroup.MarginLayoutParams lp =
                         (ViewGroup.MarginLayoutParams) previous.getLayoutParams();
@@ -647,8 +626,6 @@
 
         // Add smart actions
         for (Button current : inflatedSmartActions) {
-            current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal,
-                    current.getPaddingBottom());
             if (previous != null) {
                 ViewGroup.MarginLayoutParams lp =
                         (ViewGroup.MarginLayoutParams) previous.getLayoutParams();
diff --git a/packages/services/CameraExtensionsProxy/AndroidManifest.xml b/packages/services/CameraExtensionsProxy/AndroidManifest.xml
index 7416cba..e5f460e 100644
--- a/packages/services/CameraExtensionsProxy/AndroidManifest.xml
+++ b/packages/services/CameraExtensionsProxy/AndroidManifest.xml
@@ -2,8 +2,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.camera">
 
-    <uses-permission android:name="android.permission.CAMERA" />
-
     <application
         android:label="@string/app_name"
         android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java
index 0f05019..d44a417 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java
@@ -25,19 +25,36 @@
 import android.hardware.camera2.CameraExtensionCharacteristics;
 import android.hardware.camera2.CameraManager;
 import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.extension.CameraOutputConfig;
+import android.hardware.camera2.extension.CameraSessionConfig;
 import android.hardware.camera2.extension.CaptureBundle;
+import android.hardware.camera2.extension.CaptureFailure;
 import android.hardware.camera2.extension.CaptureStageImpl;
+import android.hardware.camera2.extension.IAdvancedExtenderImpl;
 import android.hardware.camera2.extension.ICameraExtensionsProxyService;
+import android.hardware.camera2.extension.ICaptureCallback;
 import android.hardware.camera2.extension.ICaptureProcessorImpl;
 import android.hardware.camera2.extension.IPreviewExtenderImpl;
 import android.hardware.camera2.extension.IPreviewImageProcessorImpl;
+import android.hardware.camera2.extension.IRequestCallback;
+import android.hardware.camera2.extension.IRequestProcessorImpl;
 import android.hardware.camera2.extension.IRequestUpdateProcessorImpl;
-import android.hardware.camera2.extension.ParcelImage;
 import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
+import android.hardware.camera2.extension.IImageProcessorImpl;
+import android.hardware.camera2.extension.ISessionProcessorImpl;
+import android.hardware.camera2.extension.LatencyRange;
+import android.hardware.camera2.extension.OutputConfigId;
+import android.hardware.camera2.extension.OutputSurface;
+import android.hardware.camera2.extension.ParcelCaptureResult;
+import android.hardware.camera2.extension.ParcelImage;
+import android.hardware.camera2.extension.ParcelTotalCaptureResult;
+import android.hardware.camera2.extension.Request;
 import android.hardware.camera2.extension.SizeList;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.HardwareBuffer;
+import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
 import android.media.Image;
 import android.media.ImageReader;
 import android.os.ConditionVariable;
@@ -45,9 +62,11 @@
 import android.os.HandlerExecutor;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Range;
 import android.util.Size;
 import android.view.Surface;
 
@@ -69,10 +88,26 @@
 import androidx.camera.extensions.impl.PreviewExtenderImpl.ProcessorType;
 import androidx.camera.extensions.impl.PreviewImageProcessorImpl;
 import androidx.camera.extensions.impl.RequestUpdateProcessorImpl;
+import androidx.camera.extensions.impl.advanced.AdvancedExtenderImpl;
+import androidx.camera.extensions.impl.advanced.AutoAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.advanced.BeautyAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.advanced.BokehAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.advanced.Camera2OutputConfigImpl;
+import androidx.camera.extensions.impl.advanced.Camera2SessionConfigImpl;
+import androidx.camera.extensions.impl.advanced.HdrAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.advanced.ImageProcessorImpl;
+import androidx.camera.extensions.impl.advanced.ImageReaderOutputConfigImpl;
+import androidx.camera.extensions.impl.advanced.MultiResolutionImageReaderOutputConfigImpl;
+import androidx.camera.extensions.impl.advanced.NightAdvancedExtenderImpl;
+import androidx.camera.extensions.impl.advanced.OutputSurfaceImpl;
+import androidx.camera.extensions.impl.advanced.RequestProcessorImpl;
+import androidx.camera.extensions.impl.advanced.SessionProcessorImpl;
+import androidx.camera.extensions.impl.advanced.SurfaceOutputConfigImpl;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -83,13 +118,20 @@
 
     private static final String CAMERA_EXTENSION_VERSION_NAME =
             "androidx.camera.extensions.impl.ExtensionVersionImpl";
-    private static final String LATEST_VERSION = "1.1.0";
-    private static final String[] SUPPORTED_VERSION_PREFIXES = {"1.1.", "1.0."};
+    private static final String LATEST_VERSION = "1.2.0";
+    private static final String LEGACY_VERSION_PREFIX = "1.1";
+    private static final String ADVANCED_VERSION_PREFIX = "1.2";
+    private static final String[] SUPPORTED_VERSION_PREFIXES = {ADVANCED_VERSION_PREFIX,
+            LEGACY_VERSION_PREFIX, "1.0."};
     private static final boolean EXTENSIONS_PRESENT = checkForExtensions();
     private static final String EXTENSIONS_VERSION = EXTENSIONS_PRESENT ?
             (new ExtensionVersionImpl()).checkApiVersion(LATEST_VERSION) : null;
-    private static final boolean LATEST_VERSION_SUPPORTED =
-            EXTENSIONS_PRESENT && EXTENSIONS_VERSION.startsWith(SUPPORTED_VERSION_PREFIXES[0]);
+    private static final boolean LEGACY_VERSION_SUPPORTED =
+            EXTENSIONS_PRESENT && EXTENSIONS_VERSION.startsWith(LEGACY_VERSION_PREFIX);
+    private static final boolean ADVANCED_VERSION_SUPPORTED =
+            EXTENSIONS_PRESENT && EXTENSIONS_VERSION.startsWith(ADVANCED_VERSION_PREFIX);
+
+    private HashMap<String, CameraCharacteristics> mCharacteristicsHashMap = new HashMap<>();
 
     private static boolean checkForExtensions() {
         try {
@@ -223,7 +265,7 @@
 
         public long registerClient(Context ctx) {
             synchronized (mLock) {
-                if (LATEST_VERSION_SUPPORTED) {
+                if (LEGACY_VERSION_SUPPORTED) {
                     if (mActiveClients.isEmpty()) {
                         InitializerFuture status = new InitializerFuture();
                         InitializerImpl.init(EXTENSIONS_VERSION, ctx, new InitializeHandler(status),
@@ -257,7 +299,7 @@
         public void unregisterClient(long clientId) {
             synchronized (mLock) {
                 if (mActiveClients.remove(clientId) && mActiveClients.isEmpty() &&
-                        LATEST_VERSION_SUPPORTED) {
+                        LEGACY_VERSION_SUPPORTED) {
                     InitializerFuture status = new InitializerFuture();
                     InitializerImpl.deinit(new ReleaseHandler(status),
                             new HandlerExecutor(mHandler));
@@ -321,17 +363,39 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    public static AdvancedExtenderImpl initializeAdvancedExtensionImpl(int extensionType) {
+        switch (extensionType) {
+            case CameraExtensionCharacteristics.EXTENSION_AUTOMATIC:
+                return new AutoAdvancedExtenderImpl();
+            case CameraExtensionCharacteristics.EXTENSION_BEAUTY:
+                return new BeautyAdvancedExtenderImpl();
+            case CameraExtensionCharacteristics.EXTENSION_BOKEH:
+                return new BokehAdvancedExtenderImpl();
+            case CameraExtensionCharacteristics.EXTENSION_HDR:
+                return new HdrAdvancedExtenderImpl();
+            case CameraExtensionCharacteristics.EXTENSION_NIGHT:
+                return new NightAdvancedExtenderImpl();
+            default:
+                throw new IllegalArgumentException("Unknown extension: " + extensionType);
+        }
+    }
+
     @Override
     public void onCreate() {
         super.onCreate();
         // This will setup the camera vendor tag descriptor in the service process
+        // along with all camera characteristics.
         try {
             CameraManager manager = getSystemService(CameraManager.class);
 
             String [] cameraIds = manager.getCameraIdListNoLazy();
             if (cameraIds != null) {
                 for (String cameraId : cameraIds) {
-                    CameraCharacteristics ch = manager.getCameraCharacteristics(cameraId);
+                    mCharacteristicsHashMap.put(cameraId,
+                            manager.getCameraCharacteristics(cameraId));
                 }
             }
         } catch (CameraAccessException e) {
@@ -372,6 +436,29 @@
         return ret;
     }
 
+    private static List<SizeList> initializeParcelable(
+            Map<Integer, List<android.util.Size>> sizes) {
+        if (sizes == null) {
+            return null;
+        }
+        ArrayList<SizeList> ret = new ArrayList<>(sizes.size());
+        for (Map.Entry<Integer, List<android.util.Size>> entry : sizes.entrySet()) {
+            SizeList sizeList = new SizeList();
+            sizeList.format = entry.getKey();
+            sizeList.sizes = new ArrayList<>();
+            for (android.util.Size size : entry.getValue()) {
+                android.hardware.camera2.extension.Size sz =
+                        new android.hardware.camera2.extension.Size();
+                sz.width = size.getWidth();
+                sz.height = size.getHeight();
+                sizeList.sizes.add(sz);
+            }
+            ret.add(sizeList);
+        }
+
+        return ret;
+    }
+
     private static CameraMetadataNative initializeParcelableMetadata(
             List<Pair<CaptureRequest.Key, Object>> paramList) {
         if (paramList == null) {
@@ -386,6 +473,20 @@
         return ret;
     }
 
+    private static CameraMetadataNative initializeParcelableMetadata(
+            Map<CaptureRequest.Key<?>, Object> paramMap) {
+        if (paramMap == null) {
+            return null;
+        }
+
+        CameraMetadataNative ret = new CameraMetadataNative();
+        for (Map.Entry<CaptureRequest.Key<?>, Object> param : paramMap.entrySet()) {
+            ret.set(((CaptureRequest.Key) param.getKey()), param.getValue());
+        }
+
+        return ret;
+    }
+
     private static android.hardware.camera2.extension.CaptureStageImpl initializeParcelable(
             androidx.camera.extensions.impl.CaptureStageImpl captureStage) {
         if (captureStage == null) {
@@ -400,6 +501,20 @@
         return ret;
     }
 
+    private Request initializeParcelable(RequestProcessorImpl.Request request, int requestId) {
+        Request ret = new Request();
+        ret.targetOutputConfigIds = new ArrayList<>();
+        for (int id : request.getTargetOutputConfigIds()) {
+            OutputConfigId configId = new OutputConfigId();
+            configId.id = id;
+            ret.targetOutputConfigIds.add(configId);
+        }
+        ret.templateId = request.getTemplateId();
+        ret.parameters = initializeParcelableMetadata(request.getParameters());
+        ret.requestId = requestId;
+        return ret;
+    }
+
     private class CameraExtensionsProxyServiceStub extends ICameraExtensionsProxyService.Stub {
         @Override
         public long registerClient() {
@@ -412,6 +527,23 @@
         }
 
         @Override
+        public boolean advancedExtensionsSupported() {
+            return ADVANCED_VERSION_SUPPORTED;
+        }
+
+        @Override
+        public IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType) {
+            AdvancedExtenderImpl extension;
+            try {
+                extension = initializeAdvancedExtensionImpl(extensionType);
+            } catch (IllegalArgumentException e) {
+                return null;
+            }
+
+            return new AdvancedExtenderImplStub(extension);
+        }
+
+        @Override
         public IPreviewExtenderImpl initializePreviewExtension(int extensionType) {
             Pair<PreviewExtenderImpl, ImageCaptureExtenderImpl> extension;
             try {
@@ -436,6 +568,475 @@
         }
     }
 
+    private class AdvancedExtenderImplStub extends IAdvancedExtenderImpl.Stub {
+        private final AdvancedExtenderImpl mAdvancedExtender;
+
+        public AdvancedExtenderImplStub(AdvancedExtenderImpl advancedExtender) {
+            mAdvancedExtender = advancedExtender;
+        }
+
+        @Override
+        public boolean isExtensionAvailable(String cameraId) {
+            return mAdvancedExtender.isExtensionAvailable(cameraId, mCharacteristicsHashMap);
+        }
+
+        @Override
+        public void init(String cameraId) {
+            mAdvancedExtender.init(cameraId, mCharacteristicsHashMap);
+        }
+
+        @Override
+        public List<SizeList> getSupportedPreviewOutputResolutions(String cameraId) {
+            Map<Integer, List<Size>> supportedSizesMap =
+                    mAdvancedExtender.getSupportedPreviewOutputResolutions(cameraId);
+            if (supportedSizesMap != null) {
+                return initializeParcelable(supportedSizesMap);
+            }
+
+            return null;
+        }
+
+        @Override
+        public List<SizeList> getSupportedCaptureOutputResolutions(String cameraId) {
+            Map<Integer, List<Size>> supportedSizesMap =
+                    mAdvancedExtender.getSupportedCaptureOutputResolutions(cameraId);
+            if (supportedSizesMap != null) {
+                return initializeParcelable(supportedSizesMap);
+            }
+
+            return null;
+        }
+
+        @Override
+        public LatencyRange getEstimatedCaptureLatencyRange(String cameraId,
+                android.hardware.camera2.extension.Size outputSize, int format) {
+            Size sz = new Size(outputSize.width, outputSize.height);
+            Range<Long> latencyRange = mAdvancedExtender.getEstimatedCaptureLatencyRange(cameraId,
+                    sz, format);
+            if (latencyRange != null) {
+                LatencyRange ret = new LatencyRange();
+                ret.min = latencyRange.getLower();
+                ret.max = latencyRange.getUpper();
+                return ret;
+            }
+
+            return null;
+        }
+
+        @Override
+        public ISessionProcessorImpl getSessionProcessor() {
+            return new SessionProcessorImplStub(mAdvancedExtender.createSessionProcessor());
+        }
+    }
+
+    private class CaptureCallbackStub implements SessionProcessorImpl.CaptureCallback {
+        private final ICaptureCallback mCaptureCallback;
+
+        private CaptureCallbackStub(ICaptureCallback captureCallback) {
+            mCaptureCallback = captureCallback;
+        }
+
+        @Override
+        public void onCaptureStarted(int captureSequenceId, long timestamp) {
+            if (mCaptureCallback != null) {
+                try {
+                    mCaptureCallback.onCaptureStarted(captureSequenceId, timestamp);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to notify capture start due to remote " +
+                            "exception!");
+                }
+            }
+        }
+
+        @Override
+        public void onCaptureProcessStarted(int captureSequenceId) {
+            if (mCaptureCallback != null) {
+                try {
+                    mCaptureCallback.onCaptureProcessStarted(captureSequenceId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to notify capture process start due to remote " +
+                            "exception!");
+                }
+            }
+        }
+
+        @Override
+        public void onCaptureFailed(int captureSequenceId) {
+            if (mCaptureCallback != null) {
+                try {
+                    mCaptureCallback.onCaptureFailed(captureSequenceId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to notify capture failure due to remote " +
+                            "exception!");
+                }
+            }
+        }
+
+        @Override
+        public void onCaptureSequenceCompleted(int captureSequenceId) {
+            if (mCaptureCallback != null) {
+                try {
+                    mCaptureCallback.onCaptureSequenceCompleted(captureSequenceId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to notify capture sequence end due to remote " +
+                            "exception!");
+                }
+            }
+        }
+
+        @Override
+        public void onCaptureSequenceAborted(int captureSequenceId) {
+            if (mCaptureCallback != null) {
+                try {
+                    mCaptureCallback.onCaptureSequenceAborted(captureSequenceId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to notify capture sequence abort due to remote " +
+                            "exception!");
+                }
+            }
+        }
+    }
+
+    private class RequestCallbackStub extends IRequestCallback.Stub {
+        private final List<RequestProcessorImpl.Request> mRequests;
+        private final RequestProcessorImpl.Callback mCallback;
+
+        public RequestCallbackStub(List<RequestProcessorImpl.Request> requests,
+                RequestProcessorImpl.Callback callback) {
+            mCallback = callback;
+            if (mCallback != null) {
+                mRequests = requests;
+            } else {
+                Log.w(TAG, "No valid request callbacks!");
+                mRequests = new ArrayList<>();
+            }
+        }
+
+        @Override
+        public void onCaptureStarted(int requestId, long frameNumber, long timestamp) {
+            if (mCallback != null) {
+                if (mRequests.get(requestId) != null) {
+                    mCallback.onCaptureStarted(mRequests.get(requestId), frameNumber, timestamp);
+                } else {
+                    Log.e(TAG,"Request id: " + requestId + " not found!");
+                }
+            }
+        }
+
+        @Override
+        public void onCaptureProgressed(int requestId, ParcelCaptureResult partialResult) {
+            if (mCallback != null) {
+                if (mRequests.get(requestId) != null) {
+                    CaptureResult result = new CaptureResult(partialResult.cameraId,
+                            partialResult.results, partialResult.parent, partialResult.sequenceId,
+                            partialResult.frameNumber);
+                    mCallback.onCaptureProgressed(mRequests.get(requestId), result);
+                } else {
+                    Log.e(TAG,"Request id: " + requestId + " not found!");
+                }
+            }
+        }
+
+        @Override
+        public void onCaptureCompleted(int requestId, ParcelTotalCaptureResult totalCaptureResult) {
+            if (mCallback != null) {
+                if (mRequests.get(requestId) != null) {
+                    PhysicalCaptureResultInfo[] physicalResults = new PhysicalCaptureResultInfo[0];
+                    if ((totalCaptureResult.physicalResult != null) &&
+                            (!totalCaptureResult.physicalResult.isEmpty())) {
+                        int count = totalCaptureResult.physicalResult.size();
+                        physicalResults = new PhysicalCaptureResultInfo[count];
+                        physicalResults = totalCaptureResult.physicalResult.toArray(
+                                physicalResults);
+                    }
+                    ArrayList<CaptureResult> partials = new ArrayList<>(
+                            totalCaptureResult.partials.size());
+                    for (ParcelCaptureResult parcelResult : totalCaptureResult.partials) {
+                        partials.add(new CaptureResult(parcelResult.cameraId, parcelResult.results,
+                                parcelResult.parent, parcelResult.sequenceId,
+                                parcelResult.frameNumber));
+                    }
+                    TotalCaptureResult result = new TotalCaptureResult(
+                            totalCaptureResult.logicalCameraId, totalCaptureResult.results,
+                            totalCaptureResult.parent, totalCaptureResult.sequenceId,
+                            totalCaptureResult.frameNumber, partials, totalCaptureResult.sessionId,
+                            physicalResults);
+                    mCallback.onCaptureCompleted(mRequests.get(requestId), result);
+                } else {
+                    Log.e(TAG,"Request id: " + requestId + " not found!");
+                }
+            }
+        }
+
+        @Override
+        public void onCaptureFailed(int requestId, CaptureFailure captureFailure) {
+            if (mCallback != null) {
+                if (mRequests.get(requestId) != null) {
+                    android.hardware.camera2.CaptureFailure failure =
+                            new android.hardware.camera2.CaptureFailure(captureFailure.request,
+                                    captureFailure.reason, captureFailure.dropped,
+                                    captureFailure.sequenceId, captureFailure.frameNumber,
+                                    captureFailure.errorPhysicalCameraId);
+                    mCallback.onCaptureFailed(mRequests.get(requestId), failure);
+                } else {
+                    Log.e(TAG,"Request id: " + requestId + " not found!");
+                }
+            }
+        }
+
+        @Override
+        public void onCaptureBufferLost(int requestId, long frameNumber, int outputStreamId) {
+            if (mCallback != null) {
+                if (mRequests.get(requestId) != null) {
+                    mCallback.onCaptureBufferLost(mRequests.get(requestId), frameNumber,
+                            outputStreamId);
+                } else {
+                    Log.e(TAG,"Request id: " + requestId + " not found!");
+                }
+            }
+        }
+
+        @Override
+        public void onCaptureSequenceCompleted(int sequenceId, long frameNumber) {
+            if (mCallback != null) {
+                mCallback.onCaptureSequenceCompleted(sequenceId, frameNumber);
+            }
+        }
+
+        @Override
+        public void onCaptureSequenceAborted(int sequenceId) {
+            if (mCallback != null) {
+                mCallback.onCaptureSequenceAborted(sequenceId);
+            }
+        }
+    }
+
+    private class ImageProcessorImplStub extends IImageProcessorImpl.Stub {
+        private final ImageProcessorImpl mImageProcessor;
+
+        public ImageProcessorImplStub(ImageProcessorImpl imageProcessor) {
+            mImageProcessor = imageProcessor;
+        }
+
+        @Override
+        public void onNextImageAvailable(OutputConfigId outputConfigId, ParcelImage img) {
+            if (mImageProcessor != null) {
+                mImageProcessor.onNextImageAvailable(outputConfigId.id, img.timestamp,
+                        new ImageReferenceImpl(img));
+            }
+        }
+    }
+
+    private class RequestProcessorStub implements RequestProcessorImpl {
+        private final IRequestProcessorImpl mRequestProcessor;
+
+        public RequestProcessorStub(IRequestProcessorImpl requestProcessor) {
+            mRequestProcessor = requestProcessor;
+        }
+
+        @Override
+        public void setImageProcessor(int outputConfigId,
+                ImageProcessorImpl imageProcessor) {
+            OutputConfigId  configId = new OutputConfigId();
+            configId.id = outputConfigId;
+            try {
+                mRequestProcessor.setImageProcessor(configId,
+                        new ImageProcessorImplStub(imageProcessor));
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to set image processor due to remote exception!");
+            }
+        }
+
+        @Override
+        public boolean submit(Request request, Callback callback) {
+            ArrayList<Request> requests = new ArrayList<>();
+            requests.add(request);
+            return submit(requests, callback);
+        }
+
+        @Override
+        public boolean submit(List<Request> requests, Callback callback) {
+            ArrayList<android.hardware.camera2.extension.Request> captureRequests =
+                    new ArrayList<>();
+            int requestId = 0;
+            for (Request request : requests) {
+                captureRequests.add(initializeParcelable(request, requestId));
+                requestId++;
+            }
+
+            try {
+                return mRequestProcessor.submitBurst(captureRequests,
+                        new RequestCallbackStub(requests, callback));
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to submit request due to remote exception!");
+            }
+            return false;
+        }
+
+        @Override
+        public boolean setRepeating(Request request, Callback callback) {
+            try {
+                ArrayList<Request> requests = new ArrayList<>();
+                requests.add(request);
+                return mRequestProcessor.setRepeating(initializeParcelable(request, 0),
+                        new RequestCallbackStub(requests, callback));
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to submit repeating request due to remote exception!");
+            }
+
+            return false;
+        }
+
+        @Override
+        public void abortCaptures() {
+            try {
+                mRequestProcessor.abortCaptures();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to abort requests due to remote exception!");
+            }
+        }
+
+        @Override
+        public void stopRepeating() {
+            try {
+                mRequestProcessor.stopRepeating();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to stop repeating request due to remote exception!");
+            }
+        }
+    }
+
+    private class SessionProcessorImplStub extends ISessionProcessorImpl.Stub {
+        private final SessionProcessorImpl mSessionProcessor;
+
+        public SessionProcessorImplStub(SessionProcessorImpl sessionProcessor) {
+            mSessionProcessor = sessionProcessor;
+        }
+
+        @Override
+        public CameraSessionConfig initSession(String cameraId, OutputSurface previewSurface,
+                OutputSurface burstSurface) {
+            OutputSurfaceImplStub outputPreviewSurfaceImpl =
+                    new OutputSurfaceImplStub(previewSurface);
+            OutputSurfaceImplStub outputBurstSurfaceImpl =
+                    new OutputSurfaceImplStub(burstSurface);
+
+            Camera2SessionConfigImpl sessionConfig = mSessionProcessor.initSession(cameraId,
+                    mCharacteristicsHashMap, getApplicationContext(), outputPreviewSurfaceImpl,
+                    outputBurstSurfaceImpl, null /*imageAnalysisSurfaceConfig*/);
+
+            List<Camera2OutputConfigImpl> outputConfigs = sessionConfig.getOutputConfigs();
+            CameraSessionConfig ret = new CameraSessionConfig();
+            ret.outputConfigs = new ArrayList<>();
+            for (Camera2OutputConfigImpl output : outputConfigs) {
+                CameraOutputConfig entry = new CameraOutputConfig();
+                entry.outputId = new OutputConfigId();
+                entry.outputId.id = output.getId();
+                entry.physicalCameraId = output.getPhysicalCameraId();
+                entry.surfaceGroupId = output.getSurfaceGroupId();
+                if (output instanceof SurfaceOutputConfigImpl) {
+                    SurfaceOutputConfigImpl surfaceConfig = (SurfaceOutputConfigImpl) output;
+                    entry.type = CameraOutputConfig.TYPE_SURFACE;
+                    entry.surface = surfaceConfig.getSurface();
+                } else if (output instanceof ImageReaderOutputConfigImpl) {
+                    ImageReaderOutputConfigImpl imageReaderOutputConfig =
+                            (ImageReaderOutputConfigImpl) output;
+                    entry.type = CameraOutputConfig.TYPE_IMAGEREADER;
+                    entry.size = new android.hardware.camera2.extension.Size();
+                    entry.size.width = imageReaderOutputConfig.getSize().getWidth();
+                    entry.size.height = imageReaderOutputConfig.getSize().getHeight();
+                    entry.imageFormat = imageReaderOutputConfig.getImageFormat();
+                    entry.capacity = imageReaderOutputConfig.getMaxImages();
+                } else if (output instanceof MultiResolutionImageReaderOutputConfigImpl) {
+                    MultiResolutionImageReaderOutputConfigImpl multiResReaderConfig =
+                            (MultiResolutionImageReaderOutputConfigImpl) output;
+                    entry.type = CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER;
+                    entry.imageFormat = multiResReaderConfig.getImageFormat();
+                    entry.capacity = multiResReaderConfig.getMaxImages();
+                } else {
+                    throw new IllegalStateException("Unknown output config type!");
+                }
+                List<Camera2OutputConfigImpl> sharedOutputs =
+                        output.getSurfaceSharingOutputConfigs();
+                if ((sharedOutputs != null) && (!sharedOutputs.isEmpty())) {
+                    entry.surfaceSharingOutputConfigs = new ArrayList<>();
+                    for (Camera2OutputConfigImpl sharedOutput : sharedOutputs) {
+                        OutputConfigId outputId = new OutputConfigId();
+                        outputId.id = sharedOutput.getId();
+                        entry.surfaceSharingOutputConfigs.add(outputId);
+                    }
+                }
+                ret.outputConfigs.add(entry);
+            }
+            ret.sessionTemplateId = sessionConfig.getSessionTemplateId();
+            ret.sessionParameter = initializeParcelableMetadata(
+                    sessionConfig.getSessionParameters());
+
+            return ret;
+        }
+
+        @Override
+        public void deInitSession() {
+            mSessionProcessor.deInitSession();
+        }
+
+        @Override
+        public void onCaptureSessionStart(IRequestProcessorImpl requestProcessor) {
+            mSessionProcessor.onCaptureSessionStart(new RequestProcessorStub(requestProcessor));
+        }
+
+        @Override
+        public void onCaptureSessionEnd() {
+            mSessionProcessor.onCaptureSessionEnd();
+        }
+
+        @Override
+        public int startRepeating(ICaptureCallback callback) {
+            return mSessionProcessor.startRepeating(new CaptureCallbackStub(callback));
+        }
+
+        @Override
+        public void stopRepeating() {
+            mSessionProcessor.stopRepeating();
+        }
+
+        @Override
+        public int startCapture(ICaptureCallback callback, int jpegRotation, int jpegQuality) {
+            HashMap<CaptureRequest.Key<?>, Object> paramMap = new HashMap<>();
+            paramMap.put(CaptureRequest.JPEG_ORIENTATION, jpegRotation);
+            paramMap.put(CaptureRequest.JPEG_QUALITY, jpegQuality);
+            mSessionProcessor.setParameters(paramMap);
+            return mSessionProcessor.startCapture(new CaptureCallbackStub(callback));
+        }
+    }
+
+    private class OutputSurfaceImplStub implements OutputSurfaceImpl {
+        private final Surface mSurface;
+        private final Size mSize;
+        private final int mImageFormat;
+
+        public OutputSurfaceImplStub(OutputSurface outputSurface) {
+            mSurface = outputSurface.surface;
+            mSize = new Size(outputSurface.size.width, outputSurface.size.height);
+            mImageFormat = outputSurface.imageFormat;
+        }
+
+        @Override
+        public Surface getSurface() {
+            return mSurface;
+        }
+
+        @Override
+        public Size getSize() {
+            return mSize;
+        }
+
+        @Override
+        public int getImageFormat() {
+            return mImageFormat;
+        }
+    }
+
     private class PreviewExtenderImplStub extends IPreviewExtenderImpl.Stub {
         private final PreviewExtenderImpl mPreviewExtender;
 
@@ -471,7 +1072,7 @@
 
         @Override
         public void init(String cameraId, CameraMetadataNative chars) {
-            if (LATEST_VERSION_SUPPORTED) {
+            if (LEGACY_VERSION_SUPPORTED) {
                 mPreviewExtender.init(cameraId, new CameraCharacteristics(chars));
             }
         }
@@ -535,7 +1136,7 @@
 
         @Override
         public List<SizeList> getSupportedResolutions() {
-            if (LATEST_VERSION_SUPPORTED) {
+            if (LEGACY_VERSION_SUPPORTED) {
                 List<Pair<Integer, android.util.Size[]>> sizes =
                         mPreviewExtender.getSupportedResolutions();
                 if ((sizes != null) && !sizes.isEmpty()) {
@@ -581,7 +1182,7 @@
 
         @Override
         public void init(String cameraId, CameraMetadataNative chars) {
-            if (LATEST_VERSION_SUPPORTED) {
+            if (LEGACY_VERSION_SUPPORTED) {
                 mImageExtender.init(cameraId, new CameraCharacteristics(chars));
             }
         }
@@ -627,7 +1228,7 @@
 
         @Override
         public List<SizeList> getSupportedResolutions() {
-            if (LATEST_VERSION_SUPPORTED) {
+            if (LEGACY_VERSION_SUPPORTED) {
                 List<Pair<Integer, android.util.Size[]>> sizes =
                         mImageExtender.getSupportedResolutions();
                 if ((sizes != null) && !sizes.isEmpty()) {
@@ -737,6 +1338,51 @@
         }
     }
 
+    private class ImageReferenceImpl extends ExtensionImage
+            implements androidx.camera.extensions.impl.advanced.ImageReferenceImpl {
+
+        private final Object mImageLock = new Object();
+        private int mReferenceCount;
+
+        private ImageReferenceImpl(ParcelImage parcelImage) {
+            super(parcelImage);
+            mReferenceCount = 1;
+        }
+
+        @Override
+        public boolean increment() {
+            synchronized (mImageLock) {
+                if (mReferenceCount <= 0) {
+                    return false;
+                }
+                mReferenceCount++;
+            }
+
+            return true;
+        }
+
+        @Override
+        public boolean decrement() {
+            synchronized (mImageLock) {
+                if (mReferenceCount <= 0) {
+                    return false;
+                }
+                mReferenceCount--;
+
+                if (mReferenceCount <= 0) {
+                    close();
+                }
+            }
+
+            return true;
+        }
+
+        @Override
+        public Image get() {
+            return this;
+        }
+    }
+
     private class ExtensionImage extends android.media.Image {
         private final android.hardware.camera2.extension.ParcelImage mParcelImage;
         private GraphicBuffer mGraphicBuffer;
diff --git a/services/api/current.txt b/services/api/current.txt
index 475dcf5..50f0052 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -60,6 +60,20 @@
 
 }
 
+package com.android.server.usage {
+
+  public interface StorageStatsManagerLocal {
+    method public void registerStorageStatsAugmenter(@NonNull com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter, @NonNull String);
+  }
+
+  public static interface StorageStatsManagerLocal.StorageStatsAugmenter {
+    method public void augmentStatsForPackageForUser(@NonNull android.content.pm.PackageStats, @NonNull String, @NonNull android.os.UserHandle, boolean);
+    method public void augmentStatsForUid(@NonNull android.content.pm.PackageStats, int, boolean);
+    method public void augmentStatsForUser(@NonNull android.content.pm.PackageStats, @NonNull android.os.UserHandle);
+  }
+
+}
+
 package com.android.server.wifi {
 
   public class SupplicantManager {
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 794cb93..d6ee951 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -49,6 +49,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.system.ErrnoException;
@@ -65,6 +66,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 import com.android.net.module.util.NetdUtils;
+import com.android.net.module.util.PermissionUtils;
 
 import libcore.io.IoUtils;
 
@@ -466,8 +468,7 @@
 
         /** Safety method; guards against access of other user's UserRecords */
         private void checkCallerUid(int uid) {
-            if (uid != Binder.getCallingUid()
-                    && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) {
+            if (uid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()) {
                 throw new SecurityException("Attempted access of unowned resources");
             }
         }
@@ -1105,11 +1106,15 @@
      * Checks the user-provided direction field and throws an IllegalArgumentException if it is not
      * DIRECTION_IN or DIRECTION_OUT
      */
-    private static void checkDirection(int direction) {
+    private void checkDirection(int direction) {
         switch (direction) {
             case IpSecManager.DIRECTION_OUT:
             case IpSecManager.DIRECTION_IN:
                 return;
+            case IpSecManager.DIRECTION_FWD:
+                // Only NETWORK_STACK or MAINLINE_NETWORK_STACK allowed to use forward policies
+                PermissionUtils.enforceNetworkStackPermission(mContext);
+                return;
         }
         throw new IllegalArgumentException("Invalid Direction: " + direction);
     }
@@ -1353,6 +1358,26 @@
                         ikey,
                         0xffffffff,
                         resourceId);
+
+                // Add a forwarding policy on the tunnel interface. In order to support forwarding
+                // the IpSecTunnelInterface must have a forwarding policy matching the incoming SA.
+                //
+                // Unless a IpSecTransform is also applied against this interface in DIRECTION_FWD,
+                // forwarding will be blocked by default (as would be the case if this policy was
+                // absent).
+                //
+                // This is necessary only on the tunnel interface, and not any the interface to
+                // which traffic will be forwarded to.
+                netd.ipSecAddSecurityPolicy(
+                        callerUid,
+                        selAddrFamily,
+                        IpSecManager.DIRECTION_FWD,
+                        remoteAddr,
+                        localAddr,
+                        0,
+                        ikey,
+                        0xffffffff,
+                        resourceId);
             }
 
             userRecord.mTunnelInterfaceRecords.put(
@@ -1820,7 +1845,7 @@
         int mark =
                 (direction == IpSecManager.DIRECTION_OUT)
                         ? tunnelInterfaceInfo.getOkey()
-                        : tunnelInterfaceInfo.getIkey();
+                        : tunnelInterfaceInfo.getIkey(); // Ikey also used for FWD policies
 
         try {
             // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index db36e62..c3543e7 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -361,10 +361,13 @@
         try {
             executeRescueLevelInternal(context, level, failedPackage);
             EventLogTags.writeRescueSuccess(level);
-            logCriticalInfo(Log.DEBUG,
-                    "Finished rescue level " + levelToString(level));
+            String successMsg = "Finished rescue level " + levelToString(level);
+            if (!TextUtils.isEmpty(failedPackage)) {
+                successMsg += " for package " + failedPackage;
+            }
+            logCriticalInfo(Log.DEBUG, successMsg);
         } catch (Throwable t) {
-            logRescueException(level, t);
+            logRescueException(level, failedPackage, t);
         }
     }
 
@@ -427,7 +430,7 @@
                             pm.reboot(TAG);
                         }
                     } catch (Throwable t) {
-                        logRescueException(level, t);
+                        logRescueException(level, failedPackage, t);
                     }
                 };
                 thread = new Thread(runnable);
@@ -441,7 +444,7 @@
                         try {
                             RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
                         } catch (Throwable t) {
-                            logRescueException(level, t);
+                            logRescueException(level, failedPackage, t);
                         }
                     }
                 };
@@ -455,11 +458,15 @@
         }
     }
 
-    private static void logRescueException(int level, Throwable t) {
+    private static void logRescueException(int level, @Nullable String failedPackageName,
+            Throwable t) {
         final String msg = ExceptionUtils.getCompleteMessage(t);
         EventLogTags.writeRescueFailure(level, msg);
-        logCriticalInfo(Log.ERROR,
-                "Failed rescue level " + levelToString(level) + ": " + msg);
+        String failureMsg = "Failed rescue level " + levelToString(level);
+        if (!TextUtils.isEmpty(failedPackageName)) {
+            failureMsg += " for package " + failedPackageName;
+        }
+        logCriticalInfo(Log.ERROR, failureMsg + ": " + msg);
     }
 
     private static int mapRescueLevelToUserImpact(int rescueLevel) {
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 7763ad9..a05eb68 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -469,7 +469,7 @@
         @Override
         public void setIndividualSensorPrivacy(@UserIdInt int userId, int sensor, boolean enable) {
             enforceManageSensorPrivacyPermission();
-            if (!canChangeIndividualSensorPrivacy(sensor)) {
+            if (!canChangeIndividualSensorPrivacy(userId, sensor)) {
                 return;
             }
 
@@ -500,14 +500,14 @@
             mHandler.onSensorPrivacyChanged(userId, sensor, enable);
         }
 
-        private boolean canChangeIndividualSensorPrivacy(int sensor) {
+        private boolean canChangeIndividualSensorPrivacy(@UserIdInt int userId, int sensor) {
             if (sensor == MICROPHONE && mEmergencyCallHelper.isInEmergencyCall()) {
                 // During emergency call the microphone toggle managed automatically
                 Log.i(TAG, "Can't change mic toggle during an emergency call");
                 return false;
             }
 
-            if (mKeyguardManager != null && mKeyguardManager.isDeviceLocked()) {
+            if (mKeyguardManager != null && mKeyguardManager.isDeviceLocked(userId)) {
                 Log.i(TAG, "Can't change mic/cam toggle while device is locked");
                 return false;
             }
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index df4c2cfc..2bb9084 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -432,6 +432,7 @@
             synchronized (mLock) {
                 final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot;
                 mLastSnapshot = snapshot;
+                Slog.d(TAG, "new snapshot: " + mLastSnapshot);
 
                 // Start any VCN instances as necessary
                 for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
@@ -534,7 +535,7 @@
 
     @GuardedBy("mLock")
     private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
-        Slog.v(TAG, "Starting VCN config for subGrp: " + subscriptionGroup);
+        Slog.d(TAG, "Starting VCN config for subGrp: " + subscriptionGroup);
 
         // TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
         //                    VCN.
@@ -556,7 +557,7 @@
     @GuardedBy("mLock")
     private void startOrUpdateVcnLocked(
             @NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
-        Slog.v(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup);
+        Slog.d(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup);
 
         if (mVcns.containsKey(subscriptionGroup)) {
             final Vcn vcn = mVcns.get(subscriptionGroup);
@@ -582,7 +583,7 @@
         if (!config.getProvisioningPackageName().equals(opPkgName)) {
             throw new IllegalArgumentException("Mismatched caller and VcnConfig creator");
         }
-        Slog.v(TAG, "VCN config updated for subGrp: " + subscriptionGroup);
+        Slog.d(TAG, "VCN config updated for subGrp: " + subscriptionGroup);
 
         mContext.getSystemService(AppOpsManager.class)
                 .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName());
@@ -607,7 +608,7 @@
     public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) {
         requireNonNull(subscriptionGroup, "subscriptionGroup was null");
         requireNonNull(opPkgName, "opPkgName was null");
-        Slog.v(TAG, "VCN config cleared for subGrp: " + subscriptionGroup);
+        Slog.d(TAG, "VCN config cleared for subGrp: " + subscriptionGroup);
 
         mContext.getSystemService(AppOpsManager.class)
                 .checkPackage(mDeps.getBinderCallingUid(), opPkgName);
@@ -843,8 +844,14 @@
             }
 
             final NetworkCapabilities result = ncBuilder.build();
-            return new VcnUnderlyingNetworkPolicy(
+            final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy(
                     mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
+
+            if (VDBG) {
+                Slog.d(TAG, "getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
+                        + "; and lp: " + linkProperties + "; result = " + policy);
+            }
+            return policy;
         });
     }
 
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 9835a9a..7a0a3a7 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -97,6 +97,7 @@
         "/system/bin/audioserver",
         "/system/bin/cameraserver",
         "/system/bin/drmserver",
+        "/system/bin/keystore2",
         "/system/bin/mediadrmserver",
         "/system/bin/mediaserver",
         "/system/bin/netd",
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 1bd53ae..aadb25c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -24,6 +24,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
 import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
+import static android.os.PowerExemptionManager.REASON_OPT_OUT_REQUESTED;
 import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_PLATFORM_VPN;
 import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_VPN;
 import static android.os.PowerExemptionManager.REASON_TEMP_ALLOWED_WHILE_IN_USE;
@@ -5874,7 +5875,12 @@
                 ret = REASON_OP_ACTIVATE_PLATFORM_VPN;
             }
         }
-
+        if (ret == REASON_DENIED) {
+            if (mAm.mConstants.mFgsAllowOptOut
+                    && targetService.appInfo.hasRequestForegroundServiceExemption()) {
+                ret = REASON_OPT_OUT_REQUESTED;
+            }
+        }
         return ret;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 0979585..0fff8be 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -110,6 +110,7 @@
     static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
     static final String KEY_FGS_ATOM_SAMPLE_RATE = "fgs_atom_sample_rate";
     static final String KEY_KILL_FAS_CACHED_IDLE = "kill_fas_cached_idle";
+    static final String KEY_FGS_ALLOW_OPT_OUT = "fgs_allow_opt_out";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
     private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
@@ -161,6 +162,7 @@
      */
     private static final int
             DEFAULT_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR = 1;
+    private static final boolean DEFAULT_FGS_ALLOW_OPT_OUT = false;
 
     // Flag stored in the DeviceConfig API.
     /**
@@ -493,6 +495,12 @@
      */
     volatile boolean mKillForceAppStandByAndCachedIdle = DEFAULT_KILL_FAS_CACHED_IDLE;
 
+    /**
+     * Whether to allow "opt-out" from the foreground service restrictions.
+     * (https://developer.android.com/about/versions/12/foreground-services)
+     */
+    volatile boolean mFgsAllowOptOut = DEFAULT_FGS_ALLOW_OPT_OUT;
+
     private final ActivityManagerService mService;
     private ContentResolver mResolver;
     private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -701,6 +709,9 @@
                             case KEY_KILL_FAS_CACHED_IDLE:
                                 updateKillFasCachedIdle();
                                 break;
+                            case KEY_FGS_ALLOW_OPT_OUT:
+                                updateFgsAllowOptOut();
+                                break;
                             default:
                                 break;
                         }
@@ -1040,6 +1051,13 @@
                 DEFAULT_KILL_FAS_CACHED_IDLE);
     }
 
+    private void updateFgsAllowOptOut() {
+        mFgsAllowOptOut = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_FGS_ALLOW_OPT_OUT,
+                DEFAULT_FGS_ALLOW_OPT_OUT);
+    }
+
     private void updateImperceptibleKillExemptions() {
         IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear();
         IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);
@@ -1260,6 +1278,8 @@
         pw.print("="); pw.println(mFgsAtomSampleRate);
         pw.print("  "); pw.print(KEY_PUSH_MESSAGING_OVER_QUOTA_BEHAVIOR);
         pw.print("="); pw.println(mPushMessagingOverQuotaBehavior);
+        pw.print("  "); pw.print(KEY_FGS_ALLOW_OPT_OUT);
+        pw.print("="); pw.println(mFgsAllowOptOut);
 
         pw.println();
         if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3a8b547..83cff15 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7726,16 +7726,17 @@
             ApplicationErrorReport.CrashInfo crashInfo) {
         float loadingProgress = 1;
         IncrementalMetrics incrementalMetrics = null;
-        // Notify package manager service to possibly update package state
+        // Obtain Incremental information if available
         if (r != null && r.info != null && r.info.packageName != null) {
-            final String codePath = r.info.getCodePath();
             IncrementalStatesInfo incrementalStatesInfo =
                     mPackageManagerInt.getIncrementalStatesInfo(r.info.packageName, r.uid,
                             r.userId);
             if (incrementalStatesInfo != null) {
                 loadingProgress = incrementalStatesInfo.getProgress();
             }
-            if (IncrementalManager.isIncrementalPath(codePath)) {
+            final String codePath = r.info.getCodePath();
+            if (codePath != null && !codePath.isEmpty()
+                    && IncrementalManager.isIncrementalPath(codePath)) {
                 // Report in the main log about the incremental package
                 Slog.e(TAG, "App crashed on incremental package " + r.info.packageName
                         + " which is " + ((int) (loadingProgress * 100)) + "% loaded.");
@@ -9334,7 +9335,7 @@
             pw.println("  mFgsStartTempAllowList:");
             final long currentTimeNow = System.currentTimeMillis();
             final long elapsedRealtimeNow = SystemClock.elapsedRealtime();
-            final Set<Integer> uids = mFgsStartTempAllowList.keySet();
+            final Set<Integer> uids = new ArraySet<>(mFgsStartTempAllowList.keySet());
             for (Integer uid : uids) {
                 final Pair<Long, FgsTempAllowListItem> entry = mFgsStartTempAllowList.get(uid);
                 if (entry == null) {
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index da06753..1b5483a 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -879,7 +879,7 @@
         if (TextUtils.equals(pkgName, processName)) {
             // Omit the process name here to save space
             processName = null;
-        } else if (processName != null && processName.startsWith(pkgName)) {
+        } else if (processName != null && pkgName != null && processName.startsWith(pkgName)) {
             // Strip the prefix to save space
             processName = processName.substring(pkgName.length());
         }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index f0b116c..de2c11b 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -828,6 +828,7 @@
             } else {
                 r.receiverTime = SystemClock.uptimeMillis();
                 maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
+                maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options);
                 performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                         new Intent(r.intent), r.resultCode, r.resultData,
                         r.resultExtras, r.ordered, r.initialSticky, r.userId);
@@ -911,9 +912,16 @@
         return false;
     }
 
-    final void scheduleTempAllowlistLocked(int uid, long duration, BroadcastRecord r,
-            @TempAllowListType int type, @ReasonCode int reasonCode,
-            @Nullable String reason) {
+    void maybeScheduleTempAllowlistLocked(int uid, BroadcastRecord r,
+            @Nullable BroadcastOptions brOptions) {
+        if (brOptions == null || brOptions.getTemporaryAppAllowlistDuration() <= 0) {
+            return;
+        }
+        long duration = brOptions.getTemporaryAppAllowlistDuration();
+        final @TempAllowListType int type = brOptions.getTemporaryAppAllowlistType();
+        final @ReasonCode int reasonCode = brOptions.getTemporaryAppAllowlistReasonCode();
+        final String reason = brOptions.getTemporaryAppAllowlistReason();
+
         if (duration > Integer.MAX_VALUE) {
             duration = Integer.MAX_VALUE;
         }
@@ -1344,13 +1352,6 @@
                     // r is guaranteed ordered at this point, so we know finishReceiverLocked()
                     // will get a callback and handle the activity start token lifecycle.
                 }
-                if (brOptions != null && brOptions.getTemporaryAppAllowlistDuration() > 0) {
-                    scheduleTempAllowlistLocked(filter.owningUid,
-                            brOptions.getTemporaryAppAllowlistDuration(), r,
-                            brOptions.getTemporaryAppAllowlistType(),
-                            brOptions.getTemporaryAppAllowlistReasonCode(),
-                            brOptions.getTemporaryAppAllowlistReason());
-                }
             }
             return;
         }
@@ -1646,16 +1647,9 @@
                     + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
                     + receiverUid);
         }
-
         final boolean isActivityCapable =
                 (brOptions != null && brOptions.getTemporaryAppAllowlistDuration() > 0);
-        if (isActivityCapable) {
-            scheduleTempAllowlistLocked(receiverUid,
-                    brOptions.getTemporaryAppAllowlistDuration(), r,
-                    brOptions.getTemporaryAppAllowlistType(),
-                    brOptions.getTemporaryAppAllowlistReasonCode(),
-                    brOptions.getTemporaryAppAllowlistReason());
-        }
+        maybeScheduleTempAllowlistLocked(receiverUid, r, brOptions);
 
         // Report that a component is used for explicit broadcasts.
         if (!r.intent.isExcludingStopped() && r.curComponent != null
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index cc750ce..709139e 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -838,7 +838,7 @@
                 KEY_FREEZER_DEBOUNCE_TIMEOUT, DEFAULT_FREEZER_DEBOUNCE_TIMEOUT);
 
         if (mFreezerDebounceTimeout < 0) {
-            mFullDeltaRssThrottleKb = DEFAULT_FREEZER_DEBOUNCE_TIMEOUT;
+            mFreezerDebounceTimeout = DEFAULT_FREEZER_DEBOUNCE_TIMEOUT;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index f41c364..1ecb9eb 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -31,6 +31,8 @@
 
 import libcore.io.IoUtils;
 
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
@@ -43,8 +45,12 @@
 public class LmkdConnection {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdConnection" : TAG_AM;
 
-    // lmkd reply max size in bytes
-    private static final int LMKD_REPLY_MAX_SIZE = 12;
+    /**
+     * Max LMKD reply packet length in bytes
+     * Used to hold the data for the statsd atoms logging
+     * Must be in sync with statslog.h
+     */
+    private static final int LMKD_REPLY_MAX_SIZE = 214;
 
     // connection listener interface
     interface LmkdConnectionListener {
@@ -70,7 +76,7 @@
          * @param receivedLen Size of the data received
          * @return True if the message has been handled correctly, false otherwise.
          */
-        boolean handleUnsolicitedMessage(ByteBuffer dataReceived, int receivedLen);
+        boolean handleUnsolicitedMessage(DataInputStream inputData, int receivedLen);
     }
 
     private final MessageQueue mMsgQueue;
@@ -95,6 +101,10 @@
     private final ByteBuffer mInputBuf =
             ByteBuffer.allocate(LMKD_REPLY_MAX_SIZE);
 
+    // Input stream to parse the incoming data
+    private final DataInputStream mInputData = new DataInputStream(
+            new ByteArrayInputStream(mInputBuf.array()));
+
     // object to protect mReplyBuf and to wait/notify when reply is received
     private final Object mReplyBufLock = new Object();
 
@@ -186,26 +196,32 @@
     private void processIncomingData() {
         int len = read(mInputBuf);
         if (len > 0) {
-            synchronized (mReplyBufLock) {
-                if (mReplyBuf != null) {
-                    if (mListener.isReplyExpected(mReplyBuf, mInputBuf, len)) {
-                        // copy into reply buffer
-                        mReplyBuf.put(mInputBuf.array(), 0, len);
-                        mReplyBuf.rewind();
-                        // wakeup the waiting thread
-                        mReplyBufLock.notifyAll();
-                    } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
-                        // received unexpected packet
-                        // treat this as an error
-                        mReplyBuf = null;
-                        mReplyBufLock.notifyAll();
-                        Slog.e(TAG, "Received an unexpected packet from lmkd");
+            try {
+                // reset InputStream to point into mInputBuf.array() begin
+                mInputData.reset();
+                synchronized (mReplyBufLock) {
+                    if (mReplyBuf != null) {
+                        if (mListener.isReplyExpected(mReplyBuf, mInputBuf, len)) {
+                            // copy into reply buffer
+                            mReplyBuf.put(mInputBuf.array(), 0, len);
+                            mReplyBuf.rewind();
+                            // wakeup the waiting thread
+                            mReplyBufLock.notifyAll();
+                        } else if (!mListener.handleUnsolicitedMessage(mInputData, len)) {
+                            // received unexpected packet
+                            // treat this as an error
+                            mReplyBuf = null;
+                            mReplyBufLock.notifyAll();
+                            Slog.e(TAG, "Received an unexpected packet from lmkd");
+                        }
+                    } else if (!mListener.handleUnsolicitedMessage(mInputData, len)) {
+                        // received asynchronous communication from lmkd
+                        // but we don't recognize it.
+                        Slog.w(TAG, "Received an unexpected packet from lmkd");
                     }
-                } else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
-                    // received asynchronous communication from lmkd
-                    // but we don't recognize it.
-                    Slog.w(TAG, "Received an unexpected packet from lmkd");
                 }
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to parse lmkd data buffer. Size = " + len);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
new file mode 100644
index 0000000..c702d78
--- /dev/null
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.util.Slog;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Activity manager communication with lmkd data handling and statsd atom logging
+ */
+public final class LmkdStatsReporter {
+
+    static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdStatsReporter" : TAG_AM;
+
+    public static final int KILL_OCCURRED_MSG_SIZE = 80;
+    public static final int STATE_CHANGED_MSG_SIZE = 8;
+
+    private static final int PRESSURE_AFTER_KILL = 0;
+    private static final int NOT_RESPONDING = 1;
+    private static final int LOW_SWAP_AND_THRASHING = 2;
+    private static final int LOW_MEM_AND_SWAP = 3;
+    private static final int LOW_MEM_AND_THRASHING = 4;
+    private static final int DIRECT_RECL_AND_THRASHING = 5;
+    private static final int LOW_MEM_AND_SWAP_UTIL = 6;
+
+    /**
+     * Processes the LMK_KILL_OCCURRED packet data
+     * Logs the event when LMKD kills a process to reduce memory pressure.
+     * Code: LMK_KILL_OCCURRED = 51
+     */
+    public static void logKillOccurred(DataInputStream inputData) {
+        try {
+            final long pgFault = inputData.readLong();
+            final long pgMajFault = inputData.readLong();
+            final long rssInBytes = inputData.readLong();
+            final long cacheInBytes = inputData.readLong();
+            final long swapInBytes = inputData.readLong();
+            final long processStartTimeNS = inputData.readLong();
+            final int uid = inputData.readInt();
+            final int oomScore = inputData.readInt();
+            final int minOomScore = inputData.readInt();
+            final int freeMemKb = inputData.readInt();
+            final int freeSwapKb = inputData.readInt();
+            final int killReason = inputData.readInt();
+            final String procName = inputData.readUTF();
+
+            FrameworkStatsLog.write(FrameworkStatsLog.LMK_KILL_OCCURRED, uid, procName, oomScore,
+                    pgFault, pgMajFault, rssInBytes, cacheInBytes, swapInBytes, processStartTimeNS,
+                    minOomScore, freeMemKb, freeSwapKb, mapKillReason(killReason));
+        } catch (IOException e) {
+            Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED");
+            return;
+        }
+    }
+
+    /**
+     * Processes the LMK_STATE_CHANGED packet
+     * Logs the change in LMKD state which is used as start/stop boundaries for logging
+     * LMK_KILL_OCCURRED event.
+     * Code: LMK_STATE_CHANGED = 54
+     */
+    public static void logStateChanged(int state) {
+        FrameworkStatsLog.write(FrameworkStatsLog.LMK_STATE_CHANGED, state);
+    }
+
+    private static int mapKillReason(int reason) {
+        switch (reason) {
+            case PRESSURE_AFTER_KILL:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__PRESSURE_AFTER_KILL;
+            case NOT_RESPONDING:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__NOT_RESPONDING;
+            case LOW_SWAP_AND_THRASHING:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_SWAP_AND_THRASHING;
+            case LOW_MEM_AND_SWAP:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP;
+            case LOW_MEM_AND_THRASHING:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_THRASHING;
+            case DIRECT_RECL_AND_THRASHING:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__DIRECT_RECL_AND_THRASHING;
+            case LOW_MEM_AND_SWAP_UTIL:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP_UTIL;
+            default:
+                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__UNKNOWN;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 40db086..01bbb03 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -394,6 +394,10 @@
         mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> {
             final int pid = msg.arg1;
             final int group = msg.arg2;
+            if (pid == ActivityManagerService.MY_PID) {
+                // Skip setting the process group for system_server, keep it as default.
+                return true;
+            }
             if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setProcessGroup "
                         + msg.obj + " to " + group);
diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
index a33e7e5..408c7cb 100644
--- a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
+++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
@@ -171,7 +171,7 @@
         return mFreezeExempt;
     }
 
-    @GuardedBy("mPreLock")
+    @GuardedBy("mProcLock")
     void setFreezeExempt(boolean exempt) {
         mFreezeExempt = exempt;
     }
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 5a7e14a..88bd010 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -400,7 +400,8 @@
                 loadingProgress = incrementalStatesInfo.getProgress();
             }
             final String codePath = mApp.info.getCodePath();
-            if (IncrementalManager.isIncrementalPath(codePath)) {
+            if (codePath != null && !codePath.isEmpty()
+                    && IncrementalManager.isIncrementalPath(codePath)) {
                 // Report in the main log that the incremental package is still loading
                 Slog.e(TAG, "App ANR on incremental package " + mApp.info.packageName
                         + " which is " + ((int) (loadingProgress * 100)) + "% loaded.");
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 8ea50045..0d19209e 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -140,6 +140,7 @@
 
 import dalvik.system.VMRuntime;
 
+import java.io.DataInputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -335,18 +336,25 @@
     // LMK_GETKILLCNT
     // LMK_SUBSCRIBE
     // LMK_PROCKILL
+    // LMK_UPDATE_PROPS
+    // LMK_KILL_OCCURRED
+    // LMK_STATE_CHANGED
     static final byte LMK_TARGET = 0;
     static final byte LMK_PROCPRIO = 1;
     static final byte LMK_PROCREMOVE = 2;
     static final byte LMK_PROCPURGE = 3;
     static final byte LMK_GETKILLCNT = 4;
     static final byte LMK_SUBSCRIBE = 5;
-    static final byte LMK_PROCKILL = 6; // Note: this is an unsolicated command
+    static final byte LMK_PROCKILL = 6; // Note: this is an unsolicited command
+    static final byte LMK_UPDATE_PROPS = 7;
+    static final byte LMK_KILL_OCCURRED = 8; // Msg to subscribed clients on kill occurred event
+    static final byte LMK_STATE_CHANGED = 9; // Msg to subscribed clients on state changed
 
     // Low Memory Killer Daemon command codes.
     // These must be kept in sync with async_event_type definitions in lmkd.h
     //
     static final int LMK_ASYNC_EVENT_KILL = 0;
+    static final int LMK_ASYNC_EVENT_STAT = 1;
 
     // lmkd reconnect delay in msecs
     private static final long LMKD_RECONNECT_DELAY_MS = 1000;
@@ -829,22 +837,44 @@
                         }
 
                         @Override
-                        public boolean handleUnsolicitedMessage(ByteBuffer dataReceived,
+                        public boolean handleUnsolicitedMessage(DataInputStream inputData,
                                 int receivedLen) {
                             if (receivedLen < 4) {
                                 return false;
                             }
-                            switch (dataReceived.getInt(0)) {
-                                case LMK_PROCKILL:
-                                    if (receivedLen != 12) {
+
+                            try {
+                                switch (inputData.readInt()) {
+                                    case LMK_PROCKILL:
+                                        if (receivedLen != 12) {
+                                            return false;
+                                        }
+                                        final int pid = inputData.readInt();
+                                        final int uid = inputData.readInt();
+                                        mAppExitInfoTracker.scheduleNoteLmkdProcKilled(pid, uid);
+                                        return true;
+                                    case LMK_KILL_OCCURRED:
+                                        if (receivedLen
+                                                < LmkdStatsReporter.KILL_OCCURRED_MSG_SIZE) {
+                                            return false;
+                                        }
+                                        LmkdStatsReporter.logKillOccurred(inputData);
+                                        return true;
+                                    case LMK_STATE_CHANGED:
+                                        if (receivedLen
+                                                != LmkdStatsReporter.STATE_CHANGED_MSG_SIZE) {
+                                            return false;
+                                        }
+                                        final int state = inputData.readInt();
+                                        LmkdStatsReporter.logStateChanged(state);
+                                        return true;
+                                    default:
                                         return false;
-                                    }
-                                    mAppExitInfoTracker.scheduleNoteLmkdProcKilled(
-                                            dataReceived.getInt(4), dataReceived.getInt(8));
-                                    return true;
-                                default:
-                                    return false;
+                                }
+                            } catch (IOException e) {
+                                Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED");
                             }
+                            return false;
                         }
                     }
             );
@@ -1476,6 +1506,12 @@
             buf.putInt(LMK_SUBSCRIBE);
             buf.putInt(LMK_ASYNC_EVENT_KILL);
             ostream.write(buf.array(), 0, buf.position());
+
+            // Subscribe for stats event notifications
+            buf = ByteBuffer.allocate(4 * 2);
+            buf.putInt(LMK_SUBSCRIBE);
+            buf.putInt(LMK_ASYNC_EVENT_STAT);
+            ostream.write(buf.array(), 0, buf.position());
         } catch (IOException ex) {
             return false;
         }
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 78ff67a..05c4431 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -296,9 +296,7 @@
                         FrameworkStatsLog.USER_LEVEL_HIBERNATION_STATE_CHANGED,
                         stateSnapshot.packageName,
                         userIdSnapshot,
-                        stateSnapshot.hibernated,
-                        // TODO(b/187224817): This isn't the expected value right now.
-                        stateSnapshot.lastUnhibernatedMs);
+                        stateSnapshot.hibernated);
             });
             List<UserLevelState> states = new ArrayList<>(mUserStates.get(userId).values());
             mUserDiskStores.get(userId).scheduleWriteHibernationStates(states);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 99b0d81..50515882 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -30,6 +30,7 @@
 import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.MODE_ERRORED;
 import static android.app.AppOpsManager.MODE_FOREGROUND;
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.app.AppOpsManager.NoteOpEvent;
@@ -827,6 +828,14 @@
         @GuardedBy("AppOpsService.this")
         private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mInProgressEvents;
 
+        /**
+         * Currently paused startOp events
+         *
+         * <p>Key is clientId
+         */
+        @GuardedBy("AppOpsService.this")
+        private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mPausedInProgressEvents;
+
         AttributedOp(@Nullable String tag, @NonNull Op parent) {
             this.tag = tag;
             this.parent = parent;
@@ -944,23 +953,36 @@
                 @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
                 @AppOpsManager.UidState int uidState, @OpFlags int flags,
                 boolean triggerCallbackIfNeeded) throws RemoteException {
-            if (triggerCallbackIfNeeded && !parent.isRunning()) {
+            startedOrPaused(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
+                    uidState, flags, triggerCallbackIfNeeded, true);
+        }
+
+        private void startedOrPaused(@NonNull IBinder clientId, int proxyUid,
+                @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
+                @AppOpsManager.UidState int uidState, @OpFlags int flags,
+                boolean triggerCallbackIfNeeded, boolean isStarted) throws RemoteException {
+            if (triggerCallbackIfNeeded && !parent.isRunning() && isStarted) {
                 scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
                         parent.packageName, true);
             }
 
-            if (mInProgressEvents == null) {
+
+            if (isStarted && mInProgressEvents == null) {
                 mInProgressEvents = new ArrayMap<>(1);
+            } else if (mPausedInProgressEvents == null) {
+                mPausedInProgressEvents = new ArrayMap<>(1);
             }
+            ArrayMap<IBinder, InProgressStartOpEvent> events = isStarted
+                    ? mInProgressEvents : mPausedInProgressEvents;
 
             long startTime = System.currentTimeMillis();
-            InProgressStartOpEvent event = mInProgressEvents.get(clientId);
+            InProgressStartOpEvent event = events.get(clientId);
             if (event == null) {
                 event = mInProgressStartOpEventPool.acquire(startTime,
                         SystemClock.elapsedRealtime(), clientId,
                         PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
                         proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags);
-                mInProgressEvents.put(clientId, event);
+                events.put(clientId, event);
             } else {
                 if (uidState != event.mUidState) {
                     onUidStateChanged(uidState);
@@ -969,12 +991,15 @@
 
             event.numUnfinishedStarts++;
 
-            mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
-                    tag, uidState, flags, startTime);
+            if (isStarted) {
+                mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
+                        parent.packageName, tag, uidState, flags, startTime);
+            }
+
         }
 
         /**
-         * Update state when finishOp was called
+         * Update state when finishOp was called. Will finish started ops, and delete paused ops.
          *
          * @param clientId Id of the finishOp caller
          */
@@ -983,22 +1008,32 @@
         }
 
         private void finished(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded) {
-            if (mInProgressEvents == null) {
-                Slog.wtf(TAG, "No ops running");
-                return;
-            }
+            finishOrPause(clientId, triggerCallbackIfNeeded, false);
+        }
 
-            int indexOfToken = mInProgressEvents.indexOfKey(clientId);
+        /**
+         * Update state when paused or finished is called. If pausing, it records the op as
+         * stopping in the HistoricalRegistry, but does not delete it.
+         */
+        private void finishOrPause(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded,
+                boolean isPausing) {
+            int indexOfToken = mInProgressEvents != null
+                    ? mInProgressEvents.indexOfKey(clientId) : -1;
             if (indexOfToken < 0) {
-                Slog.wtf(TAG, "No op running for the client");
+                finishPossiblyPaused(clientId, isPausing);
                 return;
             }
 
             InProgressStartOpEvent event = mInProgressEvents.valueAt(indexOfToken);
-            event.numUnfinishedStarts--;
-            if (event.numUnfinishedStarts == 0) {
-                event.finish();
-                mInProgressEvents.removeAt(indexOfToken);
+            if (!isPausing) {
+                event.numUnfinishedStarts--;
+            }
+            // If we are pausing, create a NoteOpEvent, but don't change the InProgress event
+            if (event.numUnfinishedStarts == 0 || isPausing) {
+                if (!isPausing) {
+                    event.finish();
+                    mInProgressEvents.removeAt(indexOfToken);
+                }
 
                 if (mAccessEvents == null) {
                     mAccessEvents = new LongSparseArray<>(1);
@@ -1018,20 +1053,112 @@
                         parent.packageName, tag, event.getUidState(),
                         event.getFlags(), finishedEvent.getNoteTime(), finishedEvent.getDuration());
 
-                mInProgressStartOpEventPool.release(event);
+                if (!isPausing) {
+                    mInProgressStartOpEventPool.release(event);
+                    if (mInProgressEvents.isEmpty()) {
+                        mInProgressEvents = null;
 
-                if (mInProgressEvents.isEmpty()) {
-                    mInProgressEvents = null;
-
-                    // TODO moltmann: Also callback for single attribution tag activity changes
-                    if (triggerCallbackIfNeeded && !parent.isRunning()) {
-                        scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
-                                parent.packageName, false);
+                        // TODO ntmyren: Also callback for single attribution tag activity changes
+                        if (triggerCallbackIfNeeded && !parent.isRunning()) {
+                            scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
+                                    parent.packageName, false);
+                        }
                     }
                 }
             }
         }
 
+        // Finish or pause (no-op) an already paused op
+        private void finishPossiblyPaused(@NonNull IBinder clientId, boolean isPausing) {
+            if (mPausedInProgressEvents == null) {
+                Slog.wtf(TAG, "No ops running or paused");
+                return;
+            }
+
+            int indexOfToken = mPausedInProgressEvents.indexOfKey(clientId);
+            if (indexOfToken < 0) {
+                Slog.wtf(TAG, "No op running or paused for the client");
+                return;
+            } else if (isPausing) {
+                // already paused
+                return;
+            }
+
+            // no need to record a paused event finishing.
+            InProgressStartOpEvent event = mInProgressEvents.valueAt(indexOfToken);
+            event.numUnfinishedStarts--;
+            if (event.numUnfinishedStarts == 0) {
+                mPausedInProgressEvents.removeAt(indexOfToken);
+                mInProgressStartOpEventPool.release(event);
+                if (mPausedInProgressEvents.isEmpty()) {
+                    mPausedInProgressEvents = null;
+                }
+            }
+        }
+
+        /**
+         * Create an event that will be started, if the op is unpaused.
+         */
+        public void createPaused(@NonNull IBinder clientId, int proxyUid,
+                @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
+                @AppOpsManager.UidState int uidState, @OpFlags int flags) throws RemoteException {
+            startedOrPaused(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
+                    uidState, flags, true, false);
+        }
+
+        /**
+         * Pause all currently started ops. This will create a HistoricalRegistry
+         */
+        public void pause() {
+            if (mInProgressEvents == null) {
+                return;
+            }
+
+            if (mPausedInProgressEvents == null) {
+                mPausedInProgressEvents = new ArrayMap<>(1);
+            }
+
+            for (int i = 0; i < mInProgressEvents.size(); i++) {
+                InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
+                mPausedInProgressEvents.put(event.mClientId, event);
+                finishOrPause(event.mClientId, true, true);
+            }
+            scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
+                    parent.packageName, false);
+            mInProgressEvents = null;
+        }
+
+        /**
+         * Unpause all currently paused ops. This will reinitialize their start and duration
+         * times, but keep all other values the same
+         */
+        public void resume() {
+            if (mPausedInProgressEvents == null) {
+                return;
+            }
+
+            if (mInProgressEvents == null) {
+                mInProgressEvents = new ArrayMap<>(mPausedInProgressEvents.size());
+            }
+            boolean shouldSendActive = !mPausedInProgressEvents.isEmpty()
+                    && mInProgressEvents.isEmpty();
+
+            long startTime = System.currentTimeMillis();
+            for (int i = 0; i < mPausedInProgressEvents.size(); i++) {
+                InProgressStartOpEvent event = mPausedInProgressEvents.valueAt(i);
+                mInProgressEvents.put(event.mClientId, event);
+                event.mStartElapsedTime = SystemClock.elapsedRealtime();
+                event.mStartTime = startTime;
+                mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
+                        parent.packageName, tag, event.mUidState, event.mFlags, startTime);
+            }
+            if (shouldSendActive) {
+                scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
+                        parent.packageName, true);
+            }
+            mPausedInProgressEvents = null;
+        }
+
         /**
          * Called in the case the client dies without calling finish first
          *
@@ -2303,6 +2430,9 @@
                 scheduleWriteLocked();
             }
             uidState.evalForegroundOps(mOpModeWatchers);
+            if (mode != MODE_ERRORED && mode != previousMode) {
+                updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
+            }
         }
 
         notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback);
@@ -2556,6 +2686,9 @@
                         pruneOpLocked(op, uid, packageName);
                     }
                     scheduleFastWriteLocked();
+                    if (mode != MODE_ERRORED) {
+                        updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
+                    }
                 }
             }
         }
@@ -3660,6 +3793,7 @@
                     packageName);
         }
 
+        boolean isRestricted = false;
         synchronized (this) {
             final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, true /* edit */);
             if (ops == null) {
@@ -3673,18 +3807,10 @@
                         packageName);
             }
             final Op op = getOpLocked(ops, code, uid, true);
-            if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
-                if (!dryRun) {
-                    scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                            flags, AppOpsManager.MODE_IGNORED);
-                }
-                return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
-                        packageName);
-            }
-
             final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
-            final int switchCode = AppOpsManager.opToSwitch(code);
             final UidState uidState = ops.uidState;
+            isRestricted = isOpRestrictedLocked(uid, code, packageName, bypass);
+            final int switchCode = AppOpsManager.opToSwitch(code);
             // If there is a non-default per UID policy (we set UID op mode only if
             // non-default) it takes over, otherwise use the per package policy.
             if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
@@ -3720,25 +3846,30 @@
                 }
             }
             if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
-                    + " package " + packageName);
+                    + " package " + packageName + " restricted: " + isRestricted);
             if (!dryRun) {
-                scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
-                        AppOpsManager.MODE_ALLOWED);
                 try {
-                    attributedOp.started(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
-                            uidState.state, flags);
+                    if (isRestricted) {
+                        attributedOp.createPaused(clientId, proxyUid, proxyPackageName,
+                                proxyAttributionTag, uidState.state, flags);
+                    } else {
+                        attributedOp.started(clientId, proxyUid, proxyPackageName,
+                                proxyAttributionTag, uidState.state, flags);
+                    }
                 } catch (RemoteException e) {
                     throw new RuntimeException(e);
                 }
+                scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
+                        isRestricted ? MODE_IGNORED : MODE_ALLOWED);
             }
         }
 
-        if (shouldCollectAsyncNotedOp && !dryRun) {
+        if (shouldCollectAsyncNotedOp && !dryRun && !isRestricted) {
             collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF,
                     message, shouldCollectMessage);
         }
 
-        return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag,
+        return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag,
                 packageName);
     }
 
@@ -6116,6 +6247,9 @@
             if (restrictionState.setRestriction(code, restricted, exceptionPackages, userHandle)) {
                 mHandler.sendMessage(PooledLambda.obtainMessage(
                         AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
+                mHandler.sendMessage(PooledLambda.obtainMessage(
+                        AppOpsService::updateStartedOpModeForUser, this, code, restricted,
+                        userHandle));
             }
 
             if (restrictionState.isDefault()) {
@@ -6125,6 +6259,44 @@
         }
     }
 
+    private void updateStartedOpModeForUser(int code, boolean restricted, int userId) {
+        synchronized (AppOpsService.this) {
+            int numUids = mUidStates.size();
+            for (int uidNum = 0; uidNum < numUids; uidNum++) {
+                int uid = mUidStates.keyAt(uidNum);
+                if (userId != UserHandle.USER_ALL && UserHandle.getUserId(uid) != userId) {
+                    continue;
+                }
+                updateStartedOpModeForUidLocked(code, restricted, uid);
+            }
+        }
+    }
+
+    private void updateStartedOpModeForUidLocked(int code, boolean restricted, int uid) {
+        UidState uidState = mUidStates.get(uid);
+        if (uidState == null || uidState.pkgOps == null) {
+            return;
+        }
+
+        int numPkgOps = uidState.pkgOps.size();
+        for (int pkgNum = 0; pkgNum < numPkgOps; pkgNum++) {
+            Ops ops = uidState.pkgOps.valueAt(pkgNum);
+            Op op = ops != null ? ops.get(code) : null;
+            if (op == null || (op.mode != MODE_ALLOWED && op.mode != MODE_FOREGROUND)) {
+                continue;
+            }
+            int numAttrTags = op.mAttributions.size();
+            for (int attrNum = 0; attrNum < numAttrTags; attrNum++) {
+                AttributedOp attrOp = op.mAttributions.valueAt(attrNum);
+                if (restricted) {
+                    attrOp.pause();
+                } else {
+                    attrOp.resume();
+                }
+            }
+        }
+    }
+
     private void notifyWatchersOfChange(int code, int uid) {
         final ArraySet<ModeCallback> clonedCallbacks;
         synchronized (this) {
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 5556015..35e8d34 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -555,8 +555,6 @@
                     }
                     if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE) {
                         mDiscreteRegistry.setDebugMode(true);
-                    } else {
-                        mDiscreteRegistry.setDebugMode(false);
                     }
                 }
                 if (mBaseSnapshotInterval != baseSnapshotInterval) {
@@ -627,6 +625,7 @@
         }
         setHistoryParameters(DEFAULT_MODE, DEFAULT_SNAPSHOT_INTERVAL_MILLIS,
                 DEFAULT_COMPRESSION_STEP);
+        mDiscreteRegistry.setDebugMode(false);
     }
 
     void clearHistory(int uid, String packageName) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 098ce7c..a2722cb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6535,6 +6535,10 @@
                     if (index == -1) {
                         continue;
                     }
+                    if (mPublicStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED
+                            && mCameraSoundForced) {
+                        index = mIndexMax;
+                    }
                     if (DEBUG_VOL) {
                         Log.v(TAG, "readSettings: found stored index " + getValidIndex(index)
                                  + " for group " + mAudioVolumeGroup.name() + ", device: " + name
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 677ea5d..6482a2e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -46,6 +46,7 @@
      * Interface that ClientMonitor holders should use to receive callbacks.
      */
     public interface Callback {
+
         /**
          * Invoked when the ClientMonitor operation has been started (e.g. reached the head of
          * the queue and becomes the current operation).
@@ -222,6 +223,7 @@
                 + this.getClass().getSimpleName()
                 + ", " + getProtoEnum()
                 + ", " + getOwnerString()
-                + ", " + getCookie() + "}";
+                + ", " + getCookie()
+                + ", " + getTargetUserId() + "}";
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index 62a9769..f1c786b49 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -132,11 +132,13 @@
         }
     }
 
-    public void onChallengeGenerated(int sensorId, long challenge) throws RemoteException {
+    /** Called when a challenged has been generated. */
+    public void onChallengeGenerated(int sensorId, int userId, long challenge)
+            throws RemoteException {
         if (mFaceServiceReceiver != null) {
-            mFaceServiceReceiver.onChallengeGenerated(sensorId, challenge);
+            mFaceServiceReceiver.onChallengeGenerated(sensorId, userId, challenge);
         } else if (mFingerprintServiceReceiver != null) {
-            mFingerprintServiceReceiver.onChallengeGenerated(sensorId, challenge);
+            mFingerprintServiceReceiver.onChallengeGenerated(sensorId, userId, challenge);
         }
     }
 
@@ -153,18 +155,6 @@
         }
     }
 
-    public void onChallengeInterrupted(int sensorId) throws RemoteException {
-        if (mFaceServiceReceiver != null) {
-            mFaceServiceReceiver.onChallengeInterrupted(sensorId);
-        }
-    }
-
-    public void onChallengeInterruptFinished(int sensorId) throws RemoteException {
-        if (mFaceServiceReceiver != null) {
-            mFaceServiceReceiver.onChallengeInterruptFinished(sensorId);
-        }
-    }
-
     // Fingerprint-specific callbacks for FingerprintManager only
 
     public void onUdfpsPointerDown(int sensorId) throws RemoteException {
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
index 1fcad62..3d74f36 100644
--- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -40,7 +40,7 @@
     @Override
     public void unableToStart() {
         try {
-            getListener().onChallengeGenerated(getSensorId(), 0L);
+            getListener().onChallengeGenerated(getSensorId(), getTargetUserId(), 0L);
         } catch (RemoteException e) {
             Slog.e(TAG, "Unable to send error", e);
         }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
index 8726923..57c1c74 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
@@ -110,17 +110,7 @@
         }
 
         @Override
-        public void onChallengeGenerated(int sensorId, long challenge) {
-
-        }
-
-        @Override
-        public void onChallengeInterrupted(int sensorId) {
-
-        }
-
-        @Override
-        public void onChallengeInterruptFinished(int sensorId) {
+        public void onChallengeGenerated(int sensorId, int userId, long challenge) {
 
         }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java
index 904c399..d76036b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java
@@ -52,7 +52,7 @@
 
     void onChallengeGenerated(int sensorId, int userId, long challenge) {
         try {
-            getListener().onChallengeGenerated(sensorId, challenge);
+            getListener().onChallengeGenerated(sensorId, userId, challenge);
             mCallback.onClientFinished(this, true /* success */);
         } catch (RemoteException e) {
             Slog.e(TAG, "Unable to send challenge", e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
index f806767..d0580c7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -99,17 +99,7 @@
         }
 
         @Override
-        public void onChallengeGenerated(int sensorId, long challenge) {
-
-        }
-
-        @Override
-        public void onChallengeInterrupted(int sensorId) {
-
-        }
-
-        @Override
-        public void onChallengeInterruptFinished(int sensorId) {
+        public void onChallengeGenerated(int sensorId, int userId, long challenge) {
 
         }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index f908fba..a5bb0f4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -80,6 +80,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.time.Clock;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -93,7 +94,13 @@
 public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
 
     private static final String TAG = "Face10";
+
     private static final int ENROLL_TIMEOUT_SEC = 75;
+    private static final int GENERATE_CHALLENGE_REUSE_INTERVAL_MILLIS = 60 * 1000;
+    private static final int GENERATE_CHALLENGE_COUNTER_TTL_MILLIS =
+            FaceGenerateChallengeClient.CHALLENGE_TIMEOUT_SEC * 1000;
+    @VisibleForTesting
+    public static Clock sSystemClock = Clock.systemUTC();
 
     private boolean mTestHalEnabled;
 
@@ -102,19 +109,15 @@
     @NonNull private final BiometricScheduler mScheduler;
     @NonNull private final Handler mHandler;
     @NonNull private final HalClientMonitor.LazyDaemon<IBiometricsFace> mLazyDaemon;
-    @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
     @NonNull private final LockoutHalImpl mLockoutTracker;
     @NonNull private final UsageStats mUsageStats;
     @NonNull private final Map<Integer, Long> mAuthenticatorIds;
     @Nullable private IBiometricsFace mDaemon;
     @NonNull private final HalResultController mHalResultController;
-    // If a challenge is generated, keep track of its owner. Since IBiometricsFace@1.0 only
-    // supports a single in-flight challenge, we must notify the interrupted owner that its
-    // challenge is no longer valid. The interrupted owner will be notified when the interrupter
-    // has finished.
-    @Nullable private FaceGenerateChallengeClient mCurrentChallengeOwner;
     private int mCurrentUserId = UserHandle.USER_NULL;
     private final int mSensorId;
+    private final List<Long> mGeneratedChallengeCount = new ArrayList<>();
+    private FaceGenerateChallengeClient mGeneratedChallengeCache = null;
 
     private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() {
         @Override
@@ -335,7 +338,6 @@
         mAuthenticatorIds = new HashMap<>();
         mLazyDaemon = Face10.this::getDaemon;
         mLockoutTracker = new LockoutHalImpl();
-        mLockoutResetDispatcher = lockoutResetDispatcher;
         mHalResultController = new HalResultController(sensorProps.sensorId, context, mHandler,
                 mScheduler, mLockoutTracker, lockoutResetDispatcher);
         mHalResultController.setCallback(() -> {
@@ -480,56 +482,56 @@
         return getDaemon() != null;
     }
 
+    private boolean isGeneratedChallengeCacheValid() {
+        return mGeneratedChallengeCache != null
+                && sSystemClock.millis() - mGeneratedChallengeCache.getCreatedAt()
+                < GENERATE_CHALLENGE_REUSE_INTERVAL_MILLIS;
+    }
+
+    private void incrementChallengeCount() {
+        mGeneratedChallengeCount.add(0, sSystemClock.millis());
+    }
+
+    private int decrementChallengeCount() {
+        final long now = sSystemClock.millis();
+        // ignore values that are old in case generate/revoke calls are not matched
+        // this doesn't ensure revoke if calls are mismatched but it keeps the list from growing
+        mGeneratedChallengeCount.removeIf(x -> now - x > GENERATE_CHALLENGE_COUNTER_TTL_MILLIS);
+        if (!mGeneratedChallengeCount.isEmpty()) {
+            mGeneratedChallengeCount.remove(0);
+        }
+        return mGeneratedChallengeCount.size();
+    }
+
     /**
-     * {@link IBiometricsFace} only supports a single in-flight challenge. In cases where two
-     * callers both need challenges (e.g. resetLockout right before enrollment), we need to ensure
-     * that either:
-     * 1) generateChallenge/operation/revokeChallenge is complete before the next generateChallenge
-     *    is processed by the scheduler, or
-     * 2) the generateChallenge callback provides a mechanism for notifying the caller that its
-     *    challenge has been invalidated by a subsequent caller, as well as a mechanism for
-     *    notifying the previous caller that the interrupting operation is complete (e.g. the
-     *    interrupting client's challenge has been revoked, so that the interrupted client can
-     *    start retry logic if necessary). See
-     *    {@link
-     *android.hardware.face.FaceManager.GenerateChallengeCallback#onChallengeInterruptFinished(int)}
-     * The only case of conflicting challenges is currently resetLockout --> enroll. So, the second
-     * option seems better as it prioritizes the new operation, which is user-facing.
+     * {@link IBiometricsFace} only supports a single in-flight challenge but there are cases where
+     * two callers both need challenges (e.g. resetLockout right before enrollment).
      */
     @Override
     public void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token,
             @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
         mHandler.post(() -> {
-            if (mCurrentChallengeOwner != null) {
-                final ClientMonitorCallbackConverter listener =
-                        mCurrentChallengeOwner.getListener();
-                Slog.w(TAG, "Current challenge owner: " + mCurrentChallengeOwner
-                        + ", listener: " + listener
-                        + ", interrupted by: " + opPackageName);
-                if (listener != null) {
-                    try {
-                        listener.onChallengeInterrupted(mSensorId);
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Unable to notify challenge interrupted", e);
-                    }
-                }
+            incrementChallengeCount();
+
+            if (isGeneratedChallengeCacheValid()) {
+                Slog.d(TAG, "Current challenge is cached and will be reused");
+                mGeneratedChallengeCache.reuseResult(receiver);
+                return;
             }
 
             scheduleUpdateActiveUserWithoutHandler(userId);
 
             final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext,
                     mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
-                    opPackageName, mSensorId, mCurrentChallengeOwner);
+                    opPackageName, mSensorId, sSystemClock.millis());
+            mGeneratedChallengeCache = client;
             mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
                 @Override
                 public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
                     if (client != clientMonitor) {
                         Slog.e(TAG, "scheduleGenerateChallenge onClientStarted, mismatched client."
                                 + " Expecting: " + client + ", received: " + clientMonitor);
-                        return;
                     }
-                    Slog.d(TAG, "Current challenge owner: " + client);
-                    mCurrentChallengeOwner = client;
                 }
             });
         });
@@ -539,14 +541,16 @@
     public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token,
             @NonNull String opPackageName, long challenge) {
         mHandler.post(() -> {
-            if (mCurrentChallengeOwner != null
-                    && !mCurrentChallengeOwner.getOwnerString().contentEquals(opPackageName)) {
-                Slog.e(TAG, "scheduleRevokeChallenge, package: " + opPackageName
-                        + " attempting to revoke challenge owned by: "
-                        + mCurrentChallengeOwner.getOwnerString());
+            final boolean shouldRevoke = decrementChallengeCount() == 0;
+            if (!shouldRevoke) {
+                Slog.w(TAG, "scheduleRevokeChallenge skipped - challenge still in use: "
+                        + mGeneratedChallengeCount);
                 return;
             }
 
+            Slog.d(TAG, "scheduleRevokeChallenge executing - no active clients");
+            mGeneratedChallengeCache = null;
+
             final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
                     mLazyDaemon, token, userId, opPackageName, mSensorId);
             mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
@@ -556,33 +560,6 @@
                     if (client != clientMonitor) {
                         Slog.e(TAG, "scheduleRevokeChallenge, mismatched client."
                                 + "Expecting: " + client + ", received: " + clientMonitor);
-                        return;
-                    }
-
-                    if (mCurrentChallengeOwner == null) {
-                        // Can happen if revoke is incorrectly called, for example without a
-                        // preceding generateChallenge
-                        Slog.w(TAG, "Current challenge owner is null");
-                        return;
-                    }
-
-                    final FaceGenerateChallengeClient previousChallengeOwner =
-                            mCurrentChallengeOwner.getInterruptedClient();
-                    mCurrentChallengeOwner = null;
-
-                    Slog.d(TAG, "Previous challenge owner: " + previousChallengeOwner);
-                    if (previousChallengeOwner != null) {
-                        final ClientMonitorCallbackConverter listener =
-                                previousChallengeOwner.getListener();
-                        if (listener == null) {
-                            Slog.w(TAG, "Listener is null");
-                        } else {
-                            try {
-                                listener.onChallengeInterruptFinished(mSensorId);
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "Unable to notify interrupt finished", e);
-                            }
-                        }
                     }
                 }
             });
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java
index 3e0064e4..f418104 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java
@@ -17,16 +17,20 @@
 package com.android.server.biometrics.sensors.face.hidl;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.biometrics.face.V1_0.IBiometricsFace;
+import android.hardware.face.IFaceServiceReceiver;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.internal.util.Preconditions;
 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
 import com.android.server.biometrics.sensors.GenerateChallengeClient;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Face-specific generateChallenge client supporting the
  * {@link android.hardware.biometrics.face.V1_0} HIDL interface.
@@ -34,40 +38,70 @@
 public class FaceGenerateChallengeClient extends GenerateChallengeClient<IBiometricsFace> {
 
     private static final String TAG = "FaceGenerateChallengeClient";
-    private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
+    static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
+    private static final Callback EMPTY_CALLBACK = new Callback() {
+    };
 
-    // If `this` FaceGenerateChallengeClient was invoked while an existing in-flight challenge
-    // was not revoked yet, store a reference to the interrupted client here. Notify the interrupted
-    // client when `this` challenge is revoked.
-    @Nullable private final FaceGenerateChallengeClient mInterruptedClient;
+    private final long mCreatedAt;
+    private List<IFaceServiceReceiver> mWaiting;
+    private Long mChallengeResult;
 
     FaceGenerateChallengeClient(@NonNull Context context,
             @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token,
             @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner,
-            int sensorId, @Nullable FaceGenerateChallengeClient interruptedClient) {
+            int sensorId, long now) {
         super(context, lazyDaemon, token, listener, userId, owner, sensorId);
-        mInterruptedClient = interruptedClient;
-    }
-
-    @Nullable
-    public FaceGenerateChallengeClient getInterruptedClient() {
-        return mInterruptedClient;
+        mCreatedAt = now;
+        mWaiting = new ArrayList<>();
     }
 
     @Override
     protected void startHalOperation() {
+        mChallengeResult = null;
         try {
-            final long challenge = getFreshDaemon().generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
-            try {
-                getListener().onChallengeGenerated(getSensorId(), challenge);
-                mCallback.onClientFinished(this, true /* success */);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Remote exception", e);
-                mCallback.onClientFinished(this, false /* success */);
+            mChallengeResult = getFreshDaemon().generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
+            // send the result to the original caller via mCallback and any waiting callers
+            // that called reuseResult
+            sendChallengeResult(getListener(), mCallback);
+            for (IFaceServiceReceiver receiver : mWaiting) {
+                sendChallengeResult(new ClientMonitorCallbackConverter(receiver), EMPTY_CALLBACK);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "generateChallenge failed", e);
             mCallback.onClientFinished(this, false /* success */);
+        } finally {
+            mWaiting = null;
+        }
+    }
+
+    /** @return An arbitrary time value for caching provided to the constructor. */
+    public long getCreatedAt() {
+        return mCreatedAt;
+    }
+
+    /**
+     * Reuse the result of this operation when it is available. The receiver will be notified
+     * immediately if a challenge has already been generated.
+     *
+     * @param receiver receiver to be notified of challenge result
+     */
+    public void reuseResult(@NonNull IFaceServiceReceiver receiver) {
+        if (mWaiting != null) {
+            mWaiting.add(receiver);
+        } else {
+            sendChallengeResult(new ClientMonitorCallbackConverter(receiver), EMPTY_CALLBACK);
+        }
+    }
+
+    private void sendChallengeResult(@NonNull ClientMonitorCallbackConverter receiver,
+            @NonNull Callback ownerCallback) {
+        Preconditions.checkState(mChallengeResult != null, "result not available");
+        try {
+            receiver.onChallengeGenerated(getSensorId(), getTargetUserId(), mChallengeResult);
+            ownerCallback.onClientFinished(this, true /* success */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+            ownerCallback.onClientFinished(this, false /* success */);
         }
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index e34afc0..29f2f20 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -100,7 +100,7 @@
         }
 
         @Override
-        public void onChallengeGenerated(int sensorId, long challenge) {
+        public void onChallengeGenerated(int sensorId, int userId, long challenge) {
 
         }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java
index 293b57d..6d01481 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGenerateChallengeClient.java
@@ -53,7 +53,7 @@
 
     void onChallengeGenerated(int sensorId, int userId, long challenge) {
         try {
-            getListener().onChallengeGenerated(sensorId, challenge);
+            getListener().onChallengeGenerated(sensorId, userId, challenge);
             mCallback.onClientFinished(this, true /* success */);
         } catch (RemoteException e) {
             Slog.e(TAG, "Unable to send challenge", e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index ad4f679..c00daff 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -101,7 +101,7 @@
         }
 
         @Override
-        public void onChallengeGenerated(int sensorId, long challenge) {
+        public void onChallengeGenerated(int sensorId, int userId, long challenge) {
 
         }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java
index 3584397..db2f045 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java
@@ -48,7 +48,7 @@
         try {
             final long challenge = getFreshDaemon().preEnroll();
             try {
-                getListener().onChallengeGenerated(getSensorId(), challenge);
+                getListener().onChallengeGenerated(getSensorId(), getTargetUserId(), challenge);
                 mCallback.onClientFinished(this, true /* success */);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote exception", e);
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 28f208b..5886b1a 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -338,7 +338,8 @@
             return currentPermission;
         }
         try {
-            final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
+            final PackageInfo app = mPackageManager.getPackageInfo(name,
+                    GET_PERMISSIONS | MATCH_ANY_USER);
             final boolean isNetwork = hasNetworkPermission(app);
             final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
             if (isNetwork || hasRestrictedPermission) {
@@ -664,6 +665,7 @@
                     break;
                 case INetd.PERMISSION_UNINSTALLED:
                     uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
+                    break;
                 default:
                     Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
                             + netdPermissionsAppIds.keyAt(i));
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 1261296..2c2a2bf 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -567,7 +567,11 @@
                 out.attributeLong(null, ATTR_TIMESTAMP, toWrite[i].timeStamp);
                 out.attribute(null, ATTR_PACKAGE_NAME, toWrite[i].packageName);
                 out.attributeInt(null, ATTR_USER, userSerialNo);
-                out.attribute(null, ATTR_UNIQUE_DISPLAY_ID, toWrite[i].uniqueDisplayId);
+                String uniqueDisplayId = toWrite[i].uniqueDisplayId;
+                if (uniqueDisplayId == null) {
+                    uniqueDisplayId = "";
+                }
+                out.attribute(null, ATTR_UNIQUE_DISPLAY_ID, uniqueDisplayId);
                 out.attributeFloat(null, ATTR_BATTERY_LEVEL, toWrite[i].batteryLevel);
                 out.attributeBoolean(null, ATTR_NIGHT_MODE, toWrite[i].nightMode);
                 out.attributeInt(null, ATTR_COLOR_TEMPERATURE,
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index f212698..40ab108 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -19,6 +19,8 @@
 import static com.android.server.wm.utils.RotationAnimationUtils.hasProtectedContent;
 
 import android.content.Context;
+import android.graphics.BLASTBufferQueue;
+import android.graphics.PixelFormat;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
@@ -91,6 +93,7 @@
     private int mDisplayHeight;     // real height, not rotated
     private SurfaceControl mSurfaceControl;
     private Surface mSurface;
+    private BLASTBufferQueue mBLASTBufferQueue;
     private NaturalSurfaceLayout mSurfaceLayout;
     private EGLDisplay mEglDisplay;
     private EGLConfig mEglConfig;
@@ -165,21 +168,30 @@
                     "Failed to take screenshot because internal display is disconnected");
             return false;
         }
-        boolean isWideColor = SurfaceControl.getDynamicDisplayInfo(token).activeColorMode
+        final boolean isWideColor = SurfaceControl.getDynamicDisplayInfo(token).activeColorMode
                 == Display.COLOR_MODE_DISPLAY_P3;
 
         // Set mPrepared here so if initialization fails, resources can be cleaned up.
         mPrepared = true;
 
-        SurfaceControl.ScreenshotHardwareBuffer hardwareBuffer = captureScreen();
+        final SurfaceControl.ScreenshotHardwareBuffer hardwareBuffer = captureScreen();
         if (hardwareBuffer == null) {
             dismiss();
             return false;
         }
 
-        boolean isProtected = hasProtectedContent(hardwareBuffer.getHardwareBuffer());
-        if (!(createSurfaceControl(hardwareBuffer.containsSecureLayers())
-                && createEglContext(isProtected) && createEglSurface(isProtected, isWideColor)
+        final boolean isProtected = hasProtectedContent(hardwareBuffer.getHardwareBuffer());
+        if (!createSurfaceControl(hardwareBuffer.containsSecureLayers())) {
+            dismiss();
+            return false;
+        }
+
+        // MODE_FADE use ColorLayer to implement.
+        if (mMode == MODE_FADE) {
+            return true;
+        }
+
+        if (!(createEglContext(isProtected) && createEglSurface(isProtected, isWideColor)
                 && setScreenshotTextureAndSetViewport(hardwareBuffer))) {
             dismiss();
             return false;
@@ -190,7 +202,7 @@
             return false;
         }
         try {
-            if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
+            if (!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
                 detachEglContext();
                 dismiss();
                 return false;
@@ -564,7 +576,7 @@
             if (mMode == MODE_FADE) {
                 builder.setColorLayer();
             } else {
-                builder.setBufferSize(mDisplayWidth, mDisplayHeight);
+                builder.setBLASTLayer();
             }
             mSurfaceControl = builder.build();
         } catch (OutOfResourcesException ex) {
@@ -579,9 +591,11 @@
         mSurfaceLayout.onDisplayTransaction(mTransaction);
         mTransaction.apply();
 
-        mSurface = new Surface();
-        mSurface.copyFrom(mSurfaceControl);
-
+        if (mMode != MODE_FADE) {
+            mBLASTBufferQueue = new BLASTBufferQueue("ColorFade", mSurfaceControl,
+                    mDisplayWidth, mDisplayHeight, PixelFormat.TRANSLUCENT);
+            mSurface = mBLASTBufferQueue.createSurface();
+        }
         return true;
     }
 
@@ -707,7 +721,12 @@
             mSurfaceLayout.dispose();
             mSurfaceLayout = null;
             mTransaction.remove(mSurfaceControl).apply();
-            mSurface.release();
+            if (mSurface != null) {
+                mSurface.release();
+                mBLASTBufferQueue.destroy();
+                mSurface = null;
+                mBLASTBufferQueue = null;
+            }
             mSurfaceControl = null;
             mSurfaceVisible = false;
             mSurfaceAlpha = 0f;
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index 7c013e0..609bd8b 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Typeface;
+import android.graphics.fonts.Font;
 import android.graphics.fonts.FontFamily;
 import android.graphics.fonts.FontFileUtil;
 import android.graphics.fonts.FontManager;
@@ -194,6 +195,13 @@
             }
         }
 
+        @Override
+        public void tryToCreateTypeface(File file) throws IOException {
+            Font font = new Font.Builder(file).build();
+            FontFamily family = new FontFamily.Builder(font).build();
+            new Typeface.CustomFallbackBuilder(family).build();
+        }
+
         private static ByteBuffer mmap(File file) throws IOException {
             try (FileInputStream in = new FileInputStream(file)) {
                 FileChannel fileChannel = in.getChannel();
diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
index d532605..e74dac5 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -68,6 +68,8 @@
         String buildFontFileName(File file) throws IOException;
 
         long getRevision(File file) throws IOException;
+
+        void tryToCreateTypeface(File file) throws IOException;
     }
 
     /** Interface to mock fs-verity in tests. */
@@ -372,6 +374,16 @@
                         "Failed to change mode to 711", e);
             }
             FontFileInfo fontFileInfo = validateFontFile(newFontFile);
+
+            // Try to create Typeface and treat as failure something goes wrong.
+            try {
+                mParser.tryToCreateTypeface(fontFileInfo.getFile());
+            } catch (IOException e) {
+                throw new SystemFontException(
+                        FontManager.RESULT_ERROR_INVALID_FONT_FILE,
+                        "Failed to create Typeface from file", e);
+            }
+
             FontConfig fontConfig = getSystemFontConfig();
             if (!addFileToMapIfSameOrNewer(fontFileInfo, fontConfig, false)) {
                 throw new SystemFontException(
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index cb05f8f..fefe953 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -221,7 +221,7 @@
         }
     }
 
-    private class Setting {
+    protected class Setting {
         @NonNull private final Context mContext;
         @NonNull private final @CecSettingName String mName;
         private final boolean mUserConfigurable;
@@ -566,7 +566,7 @@
         }
     }
 
-    private String retrieveValue(@NonNull Setting setting, @NonNull String defaultValue) {
+    protected String retrieveValue(@NonNull Setting setting, @NonNull String defaultValue) {
         @Storage int storage = getStorage(setting);
         String storageKey = getStorageKey(setting);
         if (storage == STORAGE_SYSPROPS) {
@@ -582,7 +582,7 @@
         return null;
     }
 
-    private void storeValue(@NonNull Setting setting, @NonNull String value) {
+    protected void storeValue(@NonNull Setting setting, @NonNull String value) {
         @Storage int storage = getStorage(setting);
         String storageKey = getStorageKey(setting);
         if (storage == STORAGE_SYSPROPS) {
@@ -626,7 +626,7 @@
         notifySettingChanged(setting);
     }
 
-    private void notifySettingChanged(@NonNull Setting setting) {
+    protected void notifySettingChanged(@NonNull Setting setting) {
         synchronized (mLock) {
             ArrayMap<SettingChangeListener, Executor> listeners =
                     mSettingChangeListeners.get(setting);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 10f6948f..dcd0eb8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -136,18 +136,19 @@
         if (!mService.isControlEnabled()) {
             return;
         }
-        if (isActiveSource()) {
-            mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
-                    mAddress, mService.getPhysicalAddress()));
-        }
         boolean wasActiveSource = isActiveSource();
-        // Invalidate the internal active source record when goes to standby
+        // Invalidate the internal active source record when going to standby
         mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
                 "HdmiCecLocalDevicePlayback#onStandby()");
         boolean mTvSendStandbyOnSleep = mService.getHdmiCecConfig().getIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP)
                     == HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED;
-        if (initiatedByCec || !mTvSendStandbyOnSleep || !wasActiveSource) {
+        if (!wasActiveSource) {
+            return;
+        }
+        if (initiatedByCec || !mTvSendStandbyOnSleep) {
+            mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(mAddress,
+                            mService.getPhysicalAddress()));
             return;
         }
         switch (standbyAction) {
@@ -167,6 +168,9 @@
                                         Constants.ADDR_BROADCAST));
                         break;
                     case HdmiControlManager.POWER_CONTROL_MODE_NONE:
+                        mService.sendCecCommand(
+                                HdmiCecMessageBuilder.buildInactiveSource(mAddress,
+                                        mService.getPhysicalAddress()));
                         break;
                 }
                 break;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
index 7226cc2..e52e32a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
@@ -90,6 +90,8 @@
         pw.println("      Set the value of a CEC setting");
         pw.println("  setsystemaudiomode, setsam [on|off]");
         pw.println("      Sets the System Audio Mode feature on or off on TV devices");
+        pw.println("  setarc [on|off]");
+        pw.println("      Sets the ARC feature on or off on TV devices");
     }
 
     private int handleShellCommand(String cmd) throws RemoteException {
@@ -106,6 +108,8 @@
             case "setsystemaudiomode":
             case "setsam":
                 return setSystemAudioMode(pw);
+            case "setarc":
+                return setArcMode(pw);
         }
 
         getErrPrintWriter().println("Unhandled command: " + cmd);
@@ -229,6 +233,27 @@
         return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
     }
 
+    private int setArcMode(PrintWriter pw) throws RemoteException {
+        if (1 > getRemainingArgsCount()) {
+            throw new IllegalArgumentException(
+                    "Please indicate if ARC mode should be turned \"on\" or \"off\".");
+        }
+
+        String arg = getNextArg();
+        if (arg.equals("on")) {
+            pw.println("Setting ARC mode on");
+            mBinderService.setArcMode(true);
+        } else if (arg.equals("off")) {
+            pw.println("Setting ARC mode off");
+            mBinderService.setArcMode(false);
+        } else {
+            throw new IllegalArgumentException(
+                    "Please indicate if ARC mode should be turned \"on\" or \"off\".");
+        }
+
+        return 0;
+    }
+
     private boolean receiveCallback(String command) {
         try {
             if (!mLatch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 172a68a..c55cf51 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -269,6 +269,13 @@
 
         mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
                 this::onLocationModeChanged);
+        mInjector.getSettingsHelper().addOnIgnoreSettingsPackageWhitelistChangedListener(
+                () -> refreshAppOpsRestrictions(UserHandle.USER_ALL));
+        mInjector.getUserInfoHelper().addListener((userId, change) -> {
+            if (change == UserInfoHelper.UserListener.USER_STARTED) {
+                refreshAppOpsRestrictions(userId);
+            }
+        });
 
         // set up passive provider first since it will be required for all other location providers,
         // which are loaded later once the system is ready.
@@ -482,6 +489,8 @@
                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+
+        refreshAppOpsRestrictions(userId);
     }
 
     @Override
@@ -1347,6 +1356,43 @@
         ipw.decreaseIndent();
     }
 
+    private void refreshAppOpsRestrictions(int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            final int[] runningUserIds = mInjector.getUserInfoHelper().getRunningUserIds();
+            for (int i = 0; i < runningUserIds.length; i++) {
+                refreshAppOpsRestrictions(runningUserIds[i]);
+            }
+            return;
+        }
+
+        Preconditions.checkArgument(userId >= 0);
+
+        ArraySet<String> packages = new ArraySet<>();
+        for (LocationProviderManager manager : mProviderManagers) {
+            packages.add(manager.getIdentity().getPackageName());
+        }
+        packages.add(mContext.getPackageName());
+        packages.addAll(mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist());
+        String[] allowedPackages = packages.toArray(new String[0]);
+
+        boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
+
+        AppOpsManager appOpsManager = Objects.requireNonNull(
+                mContext.getSystemService(AppOpsManager.class));
+        appOpsManager.setUserRestrictionForUser(
+                AppOpsManager.OP_COARSE_LOCATION,
+                enabled,
+                LocationManagerService.this,
+                allowedPackages,
+                userId);
+        appOpsManager.setUserRestrictionForUser(
+                AppOpsManager.OP_FINE_LOCATION,
+                enabled,
+                LocationManagerService.this,
+                allowedPackages,
+                userId);
+    }
+
     private class LocalService extends LocationManagerInternal {
 
         LocalService() {}
diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
index 5abc438..2bdeab4 100644
--- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
+++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
@@ -98,19 +98,7 @@
         }
 
         @Override
-        public void onChallengeInterrupted(int sensorId) {
-            Slog.w(TAG, "Challenge interrupted, sensor: " + sensorId);
-            // Consider re-attempting generateChallenge/resetLockout/revokeChallenge
-            // when onChallengeInterruptFinished is invoked
-        }
-
-        @Override
-        public void onChallengeInterruptFinished(int sensorId) {
-            Slog.w(TAG, "Challenge interrupt finished, sensor: " + sensorId);
-        }
-
-        @Override
-        public void onGenerateChallengeResult(int sensorId, long challenge) {
+        public void onGenerateChallengeResult(int sensorId, int userId, long challenge) {
             if (!sensorIds.contains(sensorId)) {
                 Slog.e(TAG, "Unknown sensorId received: " + sensorId);
                 return;
@@ -128,10 +116,6 @@
             }
 
             sensorIds.remove(sensorId);
-            // Challenge is only required for IBiometricsFace@1.0 (and not IFace AIDL). The
-            // IBiometricsFace@1.0 HAL does not require userId to revokeChallenge, so passing
-            // in 0 is OK.
-            final int userId = 0;
             faceManager.revokeChallenge(sensorId, userId, challenge);
 
             if (sensorIds.isEmpty()) {
@@ -234,18 +218,12 @@
         }
     }
 
-    /**
-     * For devices on {@link android.hardware.biometrics.face.V1_0} which only support a single
-     * in-flight challenge, we generate a single challenge to reset lockout for all profiles. This
-     * hopefully reduces/eliminates issues such as overwritten challenge, incorrectly revoked
-     * challenge, or other race conditions.
-     */
     private void processPendingLockoutsForFace(List<UserAuthInfo> pendingResetLockouts) {
         if (mFaceManager != null) {
             if (mFaceResetLockoutTask != null) {
                 // This code will need to be updated if this problem ever occurs.
-                Slog.w(TAG, "mFaceGenerateChallengeCallback not null, previous operation may be"
-                        + " stuck");
+                Slog.w(TAG,
+                        "mFaceGenerateChallengeCallback not null, previous operation may be stuck");
             }
             final List<FaceSensorPropertiesInternal> faceSensorProperties =
                     mFaceManager.getSensorPropertiesInternal();
@@ -258,12 +236,13 @@
                     mSpManager, sensorIds, pendingResetLockouts);
             for (final FaceSensorPropertiesInternal prop : faceSensorProperties) {
                 if (prop.resetLockoutRequiresHardwareAuthToken) {
-                    if (prop.resetLockoutRequiresChallenge) {
-                        // Generate a challenge for each sensor. The challenge does not need to be
-                        // per-user, since the HAT returned by gatekeeper contains userId.
-                        mFaceManager.generateChallenge(prop.sensorId, mFaceResetLockoutTask);
-                    } else {
-                        for (UserAuthInfo user : pendingResetLockouts) {
+                    for (UserAuthInfo user : pendingResetLockouts) {
+                        if (prop.resetLockoutRequiresChallenge) {
+                            Slog.d(TAG, "Generating challenge for sensor: " + prop.sensorId
+                                    + ", user: " + user.userId);
+                            mFaceManager.generateChallenge(prop.sensorId, user.userId,
+                                    mFaceResetLockoutTask);
+                        } else {
                             Slog.d(TAG, "Resetting face lockout for sensor: " + prop.sensorId
                                     + ", user: " + user.userId);
                             final byte[] hat = requestHatFromGatekeeperPassword(mSpManager, user,
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 805f395..8c1fd36 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1511,7 +1511,8 @@
 
                 builder.setSmallIcon(R.drawable.stat_notify_error);
 
-                final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
+                final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template,
+                        mContext.getPackageName());
                 builder.setDeleteIntent(PendingIntent.getBroadcast(
                         mContext, 0, snoozeIntent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
 
@@ -1597,7 +1598,8 @@
 
                 builder.setSmallIcon(R.drawable.stat_notify_error);
 
-                final Intent snoozeIntent = buildSnoozeRapidIntent(policy.template);
+                final Intent snoozeIntent = buildSnoozeRapidIntent(policy.template,
+                        mContext.getPackageName());
                 builder.setDeleteIntent(PendingIntent.getBroadcast(
                         mContext, 0, snoozeIntent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
 
@@ -5478,17 +5480,19 @@
         return new Intent(ACTION_ALLOW_BACKGROUND);
     }
 
-    private static Intent buildSnoozeWarningIntent(NetworkTemplate template) {
+    private static Intent buildSnoozeWarningIntent(NetworkTemplate template, String targetPackage) {
         final Intent intent = new Intent(ACTION_SNOOZE_WARNING);
         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
+        intent.setPackage(targetPackage);
         return intent;
     }
 
-    private static Intent buildSnoozeRapidIntent(NetworkTemplate template) {
+    private static Intent buildSnoozeRapidIntent(NetworkTemplate template, String targetPackage) {
         final Intent intent = new Intent(ACTION_SNOOZE_RAPID);
         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
+        intent.setPackage(targetPackage);
         return intent;
     }
 
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 202b315..a3daae4 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -101,6 +101,7 @@
     protected static final String ENABLED_SERVICES_SEPARATOR = ":";
     private static final String DB_VERSION_1 = "1";
     private static final String DB_VERSION_2 = "2";
+    private static final String DB_VERSION_3 = "3";
 
 
     /**
@@ -113,8 +114,9 @@
     static final String ATT_VERSION = "version";
     static final String ATT_DEFAULTS = "defaults";
     static final String ATT_USER_SET = "user_set_services";
+    static final String ATT_USER_CHANGED = "user_changed";
 
-    static final int DB_VERSION = 3;
+    static final int DB_VERSION = 4;
 
     static final int APPROVAL_BY_PACKAGE = 0;
     static final int APPROVAL_BY_COMPONENT = 1;
@@ -160,6 +162,8 @@
     @GuardedBy("mApproved")
     protected ArrayMap<Integer, ArraySet<String>> mUserSetServices = new ArrayMap<>();
 
+    protected ArrayMap<Integer, Boolean> mIsUserChanged = new ArrayMap<>();
+
     // True if approved services are stored in xml, not settings.
     private boolean mUseXml;
 
@@ -338,6 +342,7 @@
             for (int i = 0; i < N; i++) {
                 final int userId = mApproved.keyAt(i);
                 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+                final Boolean userChanged = mIsUserChanged.get(userId);
                 if (approvedByType != null) {
                     final int M = approvedByType.size();
                     for (int j = 0; j < M; j++) {
@@ -345,16 +350,20 @@
                         final ArraySet<String> approved = approvedByType.valueAt(j);
                         if (approvedByType != null && approvedByType.size() > 0) {
                             pw.println("      " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
-                                    + " (user: " + userId + " isPrimary: " + isPrimary + ")");
+                                    + " (user: " + userId + " isPrimary: " + isPrimary
+                                    + (userChanged == null ? "" : " isUserChanged: "
+                                    + userChanged) + ")");
                         }
                     }
                 }
             }
-
             pw.println("    Has user set:");
             Set<Integer> userIds = mUserSetServices.keySet();
             for (int userId : userIds) {
-                pw.println("      userId=" + userId + " value=" + mUserSetServices.get(userId));
+                if (mIsUserChanged.get(userId) == null) {
+                    pw.println("      userId=" + userId + " value="
+                            + (mUserSetServices.get(userId)));
+                }
             }
         }
 
@@ -489,13 +498,14 @@
                     continue;
                 }
                 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+                final Boolean isUserChanged = mIsUserChanged.get(approvedUserId);
                 if (approvedByType != null) {
                     final int M = approvedByType.size();
                     for (int j = 0; j < M; j++) {
                         final boolean isPrimary = approvedByType.keyAt(j);
                         final Set<String> approved = approvedByType.valueAt(j);
                         final Set<String> userSet = mUserSetServices.get(approvedUserId);
-                        if (approved != null || userSet != null) {
+                        if (approved != null || userSet != null || isUserChanged != null) {
                             String allowedItems = approved == null
                                     ? ""
                                     : String.join(ENABLED_SERVICES_SEPARATOR, approved);
@@ -503,7 +513,9 @@
                             out.attribute(null, ATT_APPROVED_LIST, allowedItems);
                             out.attributeInt(null, ATT_USER_ID, approvedUserId);
                             out.attributeBoolean(null, ATT_IS_PRIMARY, isPrimary);
-                            if (userSet != null) {
+                            if (isUserChanged != null) {
+                                out.attributeBoolean(null, ATT_USER_CHANGED, isUserChanged);
+                            } else if (userSet != null) {
                                 String userSetItems =
                                         String.join(ENABLED_SERVICES_SEPARATOR, userSet);
                                 out.attribute(null, ATT_USER_SET, userSetItems);
@@ -618,12 +630,21 @@
                             ? userId : parser.getAttributeInt(null, ATT_USER_ID, 0);
                     final boolean isPrimary =
                             parser.getAttributeBoolean(null, ATT_IS_PRIMARY, true);
-                    final String userSet = XmlUtils.readStringAttribute(parser, ATT_USER_SET);
+
+                    final String isUserChanged = XmlUtils.readStringAttribute(parser,
+                            ATT_USER_CHANGED);
+                    String userSetComponent = null;
+                    if (isUserChanged == null) {
+                        userSetComponent = XmlUtils.readStringAttribute(parser, ATT_USER_SET);
+                    } else {
+                        mIsUserChanged.put(resolvedUserId, Boolean.valueOf(isUserChanged));
+                    }
                     readExtraAttributes(tag, parser, resolvedUserId);
                     if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
-                            getPackageName(approved), resolvedUserId, getRequiredPermission())) {
+                            getPackageName(approved), resolvedUserId, getRequiredPermission())
+                            || approved.isEmpty()) {
                         if (mUm.getUserInfo(resolvedUserId) != null) {
-                            addApprovedList(approved, resolvedUserId, isPrimary, userSet);
+                            addApprovedList(approved, resolvedUserId, isPrimary, userSetComponent);
                         }
                         mUseXml = true;
                     }
@@ -634,10 +655,16 @@
         }
         boolean isOldVersion = TextUtils.isEmpty(version)
                 || DB_VERSION_1.equals(version)
-                || DB_VERSION_2.equals(version);
+                || DB_VERSION_2.equals(version)
+                || DB_VERSION_3.equals(version);
+        boolean needUpgradeUserset = DB_VERSION_3.equals(version);
         if (isOldVersion) {
             upgradeDefaultsXmlVersion();
         }
+        if (needUpgradeUserset) {
+            upgradeUserSet();
+        }
+
         rebindServices(false, USER_ALL);
     }
 
@@ -666,6 +693,8 @@
         }
     }
 
+    protected void upgradeUserSet() {};
+
     /**
      * Read extra attributes in the {@link #TAG_MANAGED_SERVICES} tag.
      */
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 67fd09b3..19c717d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -106,7 +106,6 @@
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
-import static com.android.internal.util.CollectionUtils.emptyIfNull;
 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
@@ -324,7 +323,6 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
@@ -832,7 +830,7 @@
                 learnNASPendingIntent).build();
 
 
-        return new Notification.Builder(getContext(), SystemNotificationChannels.ALERTS)
+        return new Notification.Builder(getContext(), SystemNotificationChannels.SYSTEM_CHANGES)
                 .setAutoCancel(false)
                 .setOngoing(true)
                 .setTicker(getContext().getResources().getString(title))
@@ -9467,6 +9465,27 @@
             return mDefaultFromConfig;
         }
 
+        @Override
+        protected void upgradeUserSet() {
+            for (int userId: mApproved.keySet()) {
+                ArraySet<String> userSetServices = mUserSetServices.get(userId);
+                mIsUserChanged.put(userId, (userSetServices != null && userSetServices.size() > 0));
+            }
+        }
+
+        @Override
+        protected void addApprovedList(String approved, int userId, boolean isPrimary,
+                String userSet) {
+            if (!TextUtils.isEmpty(approved)) {
+                String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
+                if (approvedArray.length > 1) {
+                    Slog.d(TAG, "More than one approved assistants");
+                    approved = approvedArray[0];
+                }
+            }
+            super.addApprovedList(approved, userId, isPrimary, userSet);
+        }
+
         public NotificationAssistants(Context context, Object lock, UserProfiles up,
                 IPackageManager pm) {
             super(context, lock, up, pm);
@@ -9641,47 +9660,12 @@
         }
 
         boolean hasUserSet(int userId) {
-            synchronized (mLock) {
-                ArraySet<String> userSetServices = mUserSetServices.get(userId);
-                if (userSetServices == null) {
-                    // Legacy case - no data means user-set, unless no assistant is set
-                    return !mApproved.isEmpty();
-                }
-                Map<Boolean, ArraySet<String>> approvedByType = emptyIfNull(mApproved.get(userId));
-                return userSetServices.containsAll(emptyIfNull(approvedByType.get(true)))
-                        && userSetServices.containsAll(emptyIfNull(approvedByType.get(false)));
-            }
+            Boolean userSet = mIsUserChanged.get(userId);
+            return (userSet != null && userSet);
         }
 
         void setUserSet(int userId, boolean set) {
-            synchronized (mLock) {
-                ArraySet<String> userSetServices = new ArraySet<>();
-                if (set) {
-                    ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
-                    if (approvedByType != null) {
-                        for (int i = 0; i < approvedByType.size(); i++) {
-                            userSetServices.addAll(approvedByType.valueAt(i));
-                        }
-                    }
-                }
-                mUserSetServices.put(userId, userSetServices);
-            }
-        }
-
-        @Override
-        protected void readExtraAttributes(String tag, TypedXmlPullParser parser, int userId)
-                throws IOException {
-            // TODO: this logic looks broken, since it's trying to convert a
-            // list into a boolean; for now we preserve the old parsing behavior
-            // to avoid a performance regression, but someone should investigate
-            final String value = parser.getAttributeValue(null, ATT_USER_SET);
-            final boolean userSet;
-            if (TextUtils.isEmpty(value)) {
-                userSet = false;
-            } else {
-                userSet = Boolean.parseBoolean(value);
-            }
-            setUserSet(userId, userSet);
+            mIsUserChanged.put(userId, set);
         }
 
         private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index af0aa76..77c1c1d 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -16,7 +16,6 @@
 
 package com.android.server.pm;
 
-import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.Nullable;
@@ -24,8 +23,11 @@
 import android.app.job.JobParameters;
 import android.app.job.JobScheduler;
 import android.app.job.JobService;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageInfo;
 import android.os.BatteryManagerInternal;
 import android.os.Environment;
@@ -35,6 +37,7 @@
 import android.os.storage.StorageManager;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FrameworkStatsLog;
@@ -63,9 +66,7 @@
     private static final int JOB_IDLE_OPTIMIZE = 800;
     private static final int JOB_POST_BOOT_UPDATE = 801;
 
-    private static final long IDLE_OPTIMIZATION_PERIOD = DEBUG
-            ? TimeUnit.MINUTES.toMillis(1)
-            : TimeUnit.DAYS.toMillis(1);
+    private static final long IDLE_OPTIMIZATION_PERIOD = TimeUnit.DAYS.toMillis(1);
 
     private static ComponentName sDexoptServiceName = new ComponentName(
             "android",
@@ -113,14 +114,24 @@
             return;
         }
 
-        JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+        final JobScheduler js = context.getSystemService(JobScheduler.class);
 
         // Schedule a one-off job which scans installed packages and updates
-        // out-of-date oat files.
-        js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
-                    .setMinimumLatency(TimeUnit.MINUTES.toMillis(10))
-                    .setOverrideDeadline(TimeUnit.MINUTES.toMillis(60))
-                    .build());
+        // out-of-date oat files. Schedule it 10 minutes after the boot complete event,
+        // so that we don't overload the boot with additional dex2oat compilations.
+        context.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                js.schedule(new JobInfo.Builder(JOB_POST_BOOT_UPDATE, sDexoptServiceName)
+                        .setMinimumLatency(TimeUnit.MINUTES.toMillis(10))
+                        .setOverrideDeadline(TimeUnit.MINUTES.toMillis(60))
+                        .build());
+                context.unregisterReceiver(this);
+                if (DEBUG) {
+                    Slog.i(TAG, "BootBgDexopt scheduled");
+                }
+            }
+        }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
 
         // Schedule a daily job which scans installed packages and compiles
         // those with fresh profiling data.
@@ -130,8 +141,8 @@
                     .setPeriodic(IDLE_OPTIMIZATION_PERIOD)
                     .build());
 
-        if (DEBUG_DEXOPT) {
-            Log.i(TAG, "Jobs scheduled");
+        if (DEBUG) {
+            Slog.d(TAG, "BgDexopt scheduled");
         }
     }
 
@@ -151,7 +162,7 @@
         @SuppressWarnings("deprecation")
         final long lowThreshold = StorageManager.from(context).getStorageLowBytes(mDataDir);
         if (lowThreshold == 0) {
-            Log.e(TAG, "Invalid low storage threshold");
+            Slog.e(TAG, "Invalid low storage threshold");
         }
 
         return lowThreshold;
@@ -198,13 +209,12 @@
             long usableSpace = mDataDir.getUsableSpace();
             if (usableSpace < lowThreshold) {
                 // Rather bail than completely fill up the disk.
-                Log.w(TAG, "Aborting background dex opt job due to low storage: " +
+                Slog.w(TAG, "Aborting background dex opt job due to low storage: " +
                         usableSpace);
                 break;
             }
-
-            if (DEBUG_DEXOPT) {
-                Log.i(TAG, "Updating package " + pkg);
+            if (DEBUG) {
+                Slog.i(TAG, "Updating package " + pkg);
             }
 
             // Update package if needed. Note that there can be no race between concurrent
@@ -236,13 +246,13 @@
             public void run() {
                 int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this);
                 if (result == OPTIMIZE_PROCESSED) {
-                    Log.i(TAG, "Idle optimizations completed.");
+                    Slog.i(TAG, "Idle optimizations completed.");
                 } else if (result == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
-                    Log.w(TAG, "Idle optimizations aborted because of space constraints.");
+                    Slog.w(TAG, "Idle optimizations aborted because of space constraints.");
                 } else if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
-                    Log.w(TAG, "Idle optimizations aborted by job scheduler.");
+                    Slog.w(TAG, "Idle optimizations aborted by job scheduler.");
                 } else {
-                    Log.w(TAG, "Idle optimizations ended with unexpected code: " + result);
+                    Slog.w(TAG, "Idle optimizations ended with unexpected code: " + result);
                 }
                 if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
                     // Abandon our timeslice and do not reschedule.
@@ -256,7 +266,7 @@
     // Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes).
     private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
             Context context) {
-        Log.i(TAG, "Performing idle optimizations");
+        Slog.i(TAG, "Performing idle optimizations");
         // If post-boot update is still running, request that it exits early.
         mExitPostBootUpdate.set(true);
         mAbortIdleOptimization.set(false);
@@ -331,11 +341,15 @@
             final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE
                     * lowStorageThreshold;
             boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
-            Log.d(TAG, "Should Downgrade " + shouldDowngrade);
+            if (DEBUG) {
+                Slog.d(TAG, "Should Downgrade " + shouldDowngrade);
+            }
             if (shouldDowngrade) {
                 Set<String> unusedPackages =
                         pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
-                Log.d(TAG, "Unsused Packages " +  String.join(",", unusedPackages));
+                if (DEBUG) {
+                    Slog.d(TAG, "Unsused Packages " +  String.join(",", unusedPackages));
+                }
 
                 if (!unusedPackages.isEmpty()) {
                     for (String pkg : unusedPackages) {
@@ -407,7 +421,9 @@
      */
     private boolean downgradePackage(PackageManagerService pm, String pkg,
             boolean isForPrimaryDex) {
-        Log.d(TAG, "Downgrading " + pkg);
+        if (DEBUG) {
+            Slog.d(TAG, "Downgrading " + pkg);
+        }
         boolean dex_opt_performed = false;
         int reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
         int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
@@ -529,7 +545,7 @@
         long usableSpace = mDataDir.getUsableSpace();
         if (usableSpace < lowStorageThreshold) {
             // Rather bail than completely fill up the disk.
-            Log.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace);
+            Slog.w(TAG, "Aborting background dex opt job due to low storage: " + usableSpace);
             return OPTIMIZE_ABORT_NO_SPACE_LEFT;
         }
 
@@ -568,8 +584,8 @@
 
     @Override
     public boolean onStartJob(JobParameters params) {
-        if (DEBUG_DEXOPT) {
-            Log.i(TAG, "onStartJob");
+        if (DEBUG) {
+            Slog.i(TAG, "onStartJob");
         }
 
         // NOTE: PackageManagerService.isStorageLow uses a different set of criteria from
@@ -577,17 +593,13 @@
         // restart with a period of ~1 minute.
         PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
         if (pm.isStorageLow()) {
-            if (DEBUG_DEXOPT) {
-                Log.i(TAG, "Low storage, skipping this run");
-            }
+            Slog.i(TAG, "Low storage, skipping this run");
             return false;
         }
 
         final ArraySet<String> pkgs = pm.getOptimizablePackages();
         if (pkgs.isEmpty()) {
-            if (DEBUG_DEXOPT) {
-                Log.i(TAG, "No packages to optimize");
-            }
+            Slog.i(TAG, "No packages to optimize");
             return false;
         }
 
@@ -603,8 +615,8 @@
 
     @Override
     public boolean onStopJob(JobParameters params) {
-        if (DEBUG_DEXOPT) {
-            Log.i(TAG, "onStopJob");
+        if (DEBUG) {
+            Slog.d(TAG, "onStopJob");
         }
 
         if (params.getJobId() == JOB_POST_BOOT_UPDATE) {
@@ -625,7 +637,7 @@
     private void notifyPinService(ArraySet<String> updatedPackages) {
         PinnerService pinnerService = LocalServices.getService(PinnerService.class);
         if (pinnerService != null) {
-            Log.i(TAG, "Pinning optimized code " + updatedPackages);
+            Slog.i(TAG, "Pinning optimized code " + updatedPackages);
             pinnerService.update(updatedPackages, false /* force */);
         }
     }
@@ -660,7 +672,7 @@
         final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days";
         String sysPropValue = SystemProperties.get(sysPropKey);
         if (sysPropValue == null || sysPropValue.isEmpty()) {
-            Log.w(TAG, "SysProp " + sysPropKey + " not set");
+            Slog.w(TAG, "SysProp " + sysPropKey + " not set");
             return Long.MAX_VALUE;
         }
         return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a688868..679042f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -557,6 +557,7 @@
     private static final int SHELL_UID = Process.SHELL_UID;
     private static final int SE_UID = Process.SE_UID;
     private static final int NETWORKSTACK_UID = Process.NETWORK_STACK_UID;
+    private static final int UWB_UID = Process.UWB_UID;
 
     static final int SCAN_NO_DEX = 1 << 0;
     static final int SCAN_UPDATE_SIGNATURE = 1 << 1;
@@ -6313,6 +6314,8 @@
                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+        mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,
+                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         t.traceEnd();
 
         String separateProcesses = SystemProperties.get("debug.separate_processes");
@@ -12131,6 +12134,8 @@
     public boolean performDexOptMode(String packageName,
             boolean checkProfiles, String targetCompilerFilter, boolean force,
             boolean bootComplete, String splitName) {
+        enforceSystemOrRootOrShell("performDexOptMode");
+
         int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) |
                 (force ? DexoptOptions.DEXOPT_FORCE : 0) |
                 (bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 7f18c4b..20f35f2 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2254,24 +2254,6 @@
     }
 
     @Override
-    public AndroidFuture updateShortcutVisibility(String callingPkg, String packageName,
-            byte[] certificate, boolean visible, int userId) {
-        final AndroidFuture<Void> ret = new AndroidFuture<>();
-        injectPostToHandlerIfAppSearch(() -> {
-            try {
-                synchronized (mLock) {
-                    getPackageShortcutsForPublisherLocked(callingPkg, userId)
-                            .updateVisibility(packageName, certificate, visible);
-                }
-                ret.complete(null);
-            } catch (Exception e) {
-                ret.completeExceptionally(e);
-            }
-        });
-        return ret;
-    }
-
-    @Override
     public AndroidFuture requestPinShortcut(String packageName, ShortcutInfo shortcut,
             IntentSender resultIntent, int userId) {
         final AndroidFuture<Boolean> ret = new AndroidFuture<>();
diff --git a/services/core/java/com/android/server/policy/GlobalKeyIntent.java b/services/core/java/com/android/server/policy/GlobalKeyIntent.java
new file mode 100644
index 0000000..f8682be
--- /dev/null
+++ b/services/core/java/com/android/server/policy/GlobalKeyIntent.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.util.Log;
+import android.view.KeyEvent;
+
+/**
+ * This class wrapped the Intent for global key ops.
+ */
+public final class GlobalKeyIntent {
+    private static final String EXTRA_BEGAN_FROM_NON_INTERACTIVE =
+            "EXTRA_BEGAN_FROM_NON_INTERACTIVE";
+
+    private final ComponentName mComponentName;
+    private final KeyEvent mKeyEvent;
+    private final boolean mBeganFromNonInteractive;
+
+    GlobalKeyIntent(@NonNull ComponentName componentName, @NonNull KeyEvent event,
+            boolean beganFromNonInteractive) {
+        mComponentName = componentName;
+        mKeyEvent = new KeyEvent(event);
+        mBeganFromNonInteractive = beganFromNonInteractive;
+    }
+
+    Intent getIntent() {
+        final Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON)
+                .setComponent(mComponentName)
+                .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+                .putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent)
+                .putExtra(EXTRA_BEGAN_FROM_NON_INTERACTIVE, mBeganFromNonInteractive);
+        return intent;
+    }
+
+    /**
+     * Get the {@link KeyEvent} information of {@link Intent#ACTION_GLOBAL_BUTTON}.
+     */
+    public KeyEvent getKeyEvent() {
+        return mKeyEvent;
+    }
+
+    /**
+     * Indicate if the global key is dispatched from non-interactive mode.
+     * Information of {@link Intent#ACTION_GLOBAL_BUTTON}.
+     */
+    public boolean beganFromNonInteractive() {
+        return mBeganFromNonInteractive;
+    }
+
+    /**
+     * Generate a GlobalKeyIntent from {@link Intent}, the action must be
+     * {@link Intent#ACTION_GLOBAL_BUTTON}.
+     *
+     * @param intent The received intent of the global key.
+     */
+    public static GlobalKeyIntent from(@NonNull Intent intent) {
+        if (intent.getAction() != Intent.ACTION_GLOBAL_BUTTON) {
+            Log.wtf("GlobalKeyIntent", "Intent should be ACTION_GLOBAL_BUTTON");
+            return null;
+        }
+
+        final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+        final boolean fromNonInteractive =
+                intent.getBooleanExtra(EXTRA_BEGAN_FROM_NON_INTERACTIVE, false);
+        return new GlobalKeyIntent(intent.getComponent(), event, fromNonInteractive);
+    }
+}
diff --git a/services/core/java/com/android/server/policy/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
index 157f825..2d48452 100644
--- a/services/core/java/com/android/server/policy/GlobalKeyManager.java
+++ b/services/core/java/com/android/server/policy/GlobalKeyManager.java
@@ -39,6 +39,9 @@
  * broadcast to the specified component. The action of the intent will be
  * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with
  * {@link Intent#EXTRA_KEY_EVENT}.
+ *
+ * Use {@link GlobalKeyIntent} to get detail information from received {@link Intent}, includes
+ * {@link KeyEvent} and the information about if the key is dispatched from non-interactive mode.
  */
 final class GlobalKeyManager {
 
@@ -49,13 +52,15 @@
     private static final String TAG_KEY = "key";
     private static final String ATTR_KEY_CODE = "keyCode";
     private static final String ATTR_COMPONENT = "component";
+    private static final String ATTR_DISPATCH_WHEN_NON_INTERACTIVE = "dispatchWhenNonInteractive";
 
     private static final int GLOBAL_KEY_FILE_VERSION = 1;
 
-    private SparseArray<ComponentName> mKeyMapping;
+    private SparseArray<GlobalKeyAction> mKeyMapping;
+    private boolean mBeganFromNonInteractive = false;
 
     public GlobalKeyManager(Context context) {
-        mKeyMapping = new SparseArray<ComponentName>();
+        mKeyMapping = new SparseArray<>();
         loadGlobalKeys(context);
     }
 
@@ -69,13 +74,15 @@
      */
     boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) {
         if (mKeyMapping.size() > 0) {
-            ComponentName component = mKeyMapping.get(keyCode);
-            if (component != null) {
-                Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON)
-                        .setComponent(component)
-                        .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                        .putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(event));
+            GlobalKeyAction action = mKeyMapping.get(keyCode);
+            if (action != null) {
+                final Intent intent = new GlobalKeyIntent(action.mComponentName, event,
+                        mBeganFromNonInteractive).getIntent();
                 context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);
+
+                if (event.getAction() == KeyEvent.ACTION_UP) {
+                    mBeganFromNonInteractive = false;
+                }
                 return true;
             }
         }
@@ -85,10 +92,35 @@
     /**
      * Returns {@code true} if the key will be handled globally.
      */
-    boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) {
+    boolean shouldHandleGlobalKey(int keyCode) {
         return mKeyMapping.get(keyCode) != null;
     }
 
+    /**
+     * Returns {@code true} if the key will be handled globally.
+     */
+    boolean shouldDispatchFromNonInteractive(int keyCode) {
+        final GlobalKeyAction action = mKeyMapping.get(keyCode);
+        if (action == null) {
+            return false;
+        }
+
+        return action.mDispatchWhenNonInteractive;
+    }
+
+    void setBeganFromNonInteractive() {
+        mBeganFromNonInteractive = true;
+    }
+
+    class GlobalKeyAction {
+        private ComponentName mComponentName;
+        private boolean mDispatchWhenNonInteractive;
+        GlobalKeyAction(String componentName, String dispatchWhenNonInteractive) {
+            mComponentName = ComponentName.unflattenFromString(componentName);
+            mDispatchWhenNonInteractive = Boolean.valueOf(dispatchWhenNonInteractive);
+        }
+    }
+
     private void loadGlobalKeys(Context context) {
         XmlResourceParser parser = null;
         try {
@@ -105,10 +137,12 @@
                     if (TAG_KEY.equals(element)) {
                         String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE);
                         String componentName = parser.getAttributeValue(null, ATTR_COMPONENT);
+                        String dispatchWhenNonInteractive =
+                                parser.getAttributeValue(null, ATTR_DISPATCH_WHEN_NON_INTERACTIVE);
                         int keyCode = KeyEvent.keyCodeFromString(keyCodeName);
                         if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
-                            mKeyMapping.put(keyCode, ComponentName.unflattenFromString(
-                                    componentName));
+                            mKeyMapping.put(keyCode, new GlobalKeyAction(
+                                    componentName, dispatchWhenNonInteractive));
                         }
                     }
                 }
@@ -138,7 +172,9 @@
             pw.print(prefix);
             pw.print(KeyEvent.keyCodeToString(mKeyMapping.keyAt(i)));
             pw.print("=");
-            pw.println(mKeyMapping.valueAt(i).flattenToString());
+            pw.print(mKeyMapping.valueAt(i).mComponentName.flattenToString());
+            pw.print(",dispatchWhenNonInteractive=");
+            pw.println(mKeyMapping.valueAt(i).mDispatchWhenNonInteractive);
         }
         pw.print(prefix); pw.println("}");
     }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b56736e..d73203d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3434,7 +3434,16 @@
         // If the key would be handled globally, just return the result, don't worry about special
         // key processing.
         if (isValidGlobalKey(keyCode)
-                && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
+                && mGlobalKeyManager.shouldHandleGlobalKey(keyCode)) {
+            // Dispatch if global key defined dispatchWhenNonInteractive.
+            if (!interactive && isWakeKey && down
+                    && mGlobalKeyManager.shouldDispatchFromNonInteractive(keyCode)) {
+                mGlobalKeyManager.setBeganFromNonInteractive();
+                result = ACTION_PASS_TO_USER;
+                // Since we're dispatching the input, reset the pending key
+                mPendingWakeKey = PENDING_KEY_NULL;
+            }
+
             if (isWakeKey) {
                 wakeUpFromWakeKey(event);
             }
@@ -3988,6 +3997,7 @@
                 Slog.e(TAG, "RemoteException when checking if dreaming", e);
             }
         }
+
         // Otherwise, consume events since the user can't see what is being
         // interacted with.
         return false;
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 12e55e5..ed4a7bf 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -27,6 +27,7 @@
 import static android.ota.nano.OtaPackageMetadata.ApexMetadata;
 
 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
+import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER;
 
 import android.annotation.IntDef;
 import android.apex.CompressedApexInfo;
@@ -398,7 +399,13 @@
 
     @VisibleForTesting
     void onSystemServicesReady() {
-        mInjector.getLockSettingsService().setRebootEscrowListener(this);
+        LockSettingsInternal lockSettings = mInjector.getLockSettingsService();
+        if (lockSettings == null) {
+            Slog.e(TAG, "Failed to get lock settings service, skipping set"
+                    + " RebootEscrowListener");
+            return;
+        }
+        lockSettings.setRebootEscrowListener(this);
     }
 
     @Override // Binder call
@@ -564,12 +571,18 @@
             case ROR_NEED_PREPARATION:
                 final long origId = Binder.clearCallingIdentity();
                 try {
-                    boolean result = mInjector.getLockSettingsService().prepareRebootEscrow();
-                    // Clear the RoR preparation state if lock settings reports an failure.
-                    if (!result) {
-                        clearRoRPreparationState();
+                    LockSettingsInternal lockSettings = mInjector.getLockSettingsService();
+                    if (lockSettings == null) {
+                        Slog.e(TAG, "Failed to get lock settings service, skipping"
+                                + " prepareRebootEscrow");
+                        return false;
                     }
-                    return result;
+                    // Clear the RoR preparation state if lock settings reports an failure.
+                    if (!lockSettings.prepareRebootEscrow()) {
+                        clearRoRPreparationState();
+                        return false;
+                    }
+                    return true;
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }
@@ -684,7 +697,14 @@
             case ROR_REQUESTED_NEED_CLEAR:
                 final long origId = Binder.clearCallingIdentity();
                 try {
-                    return mInjector.getLockSettingsService().clearRebootEscrow();
+                    LockSettingsInternal lockSettings = mInjector.getLockSettingsService();
+                    if (lockSettings == null) {
+                        Slog.e(TAG, "Failed to get lock settings service, skipping"
+                                + " clearRebootEscrow");
+                        return false;
+                    }
+
+                    return lockSettings.clearRebootEscrow();
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }
@@ -778,7 +798,15 @@
         final long origId = Binder.clearCallingIdentity();
         int providerErrorCode;
         try {
-            providerErrorCode = mInjector.getLockSettingsService().armRebootEscrow();
+            LockSettingsInternal lockSettings = mInjector.getLockSettingsService();
+            if (lockSettings == null) {
+                Slog.e(TAG, "Failed to get lock settings service, skipping"
+                        + " armRebootEscrow");
+                return new RebootPreparationError(
+                        RESUME_ON_REBOOT_REBOOT_ERROR_PROVIDER_PREPARATION_FAILURE,
+                        ARM_REBOOT_ERROR_NO_PROVIDER);
+            }
+            providerErrorCode = lockSettings.armRebootEscrow();
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
index 1dbe3e4..81bf29b 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
@@ -19,24 +19,20 @@
 import static android.service.rotationresolver.RotationResolverService.ROTATION_RESULT_FAILURE_CANCELLED;
 
 import static com.android.server.rotationresolver.RotationResolverManagerService.RESOLUTION_UNAVAILABLE;
-import static com.android.server.rotationresolver.RotationResolverManagerService.getServiceConfigPackage;
 import static com.android.server.rotationresolver.RotationResolverManagerService.logRotationStats;
 
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.AppGlobals;
 import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.os.CancellationSignal;
+import android.os.RemoteException;
 import android.rotationresolver.RotationResolverInternal;
 import android.service.rotationresolver.RotationResolutionRequest;
-import android.service.rotationresolver.RotationResolverService;
-import android.text.TextUtils;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
 
@@ -65,7 +61,6 @@
     @GuardedBy("mLock")
     RemoteRotationResolverService mRemoteService;
 
-    private static String sTestingPackage;
     private ComponentName mComponentName;
 
     RotationResolverManagerPerUserService(@NonNull RotationResolverManagerService main,
@@ -139,18 +134,6 @@
     }
 
     /**
-     * Set the testing package name.
-     *
-     * @param packageName the name of the package that implements {@link RotationResolverService}
-     *                    and is used for testing only.
-     */
-    @VisibleForTesting
-    void setTestingPackage(String packageName) {
-        sTestingPackage = packageName;
-        mComponentName = resolveRotationResolverService(getContext());
-    }
-
-    /**
      * get the currently bound component name.
      */
     @VisibleForTesting
@@ -158,63 +141,40 @@
         return mComponentName;
     }
 
-    /**
-     * Provides rotation resolver service component name at runtime, making sure it's provided
-     * by the system.
-     */
-    static ComponentName resolveRotationResolverService(Context context) {
-        String resolvedPackage;
-        int flags = PackageManager.MATCH_SYSTEM_ONLY;
-        if (!TextUtils.isEmpty(sTestingPackage)) {
-            // Testing Package is set.
-            resolvedPackage = sTestingPackage;
-            flags = PackageManager.GET_META_DATA;
-        } else {
-            final String serviceConfigPackage = getServiceConfigPackage(context);
-            if (!TextUtils.isEmpty(serviceConfigPackage)) {
-                resolvedPackage = serviceConfigPackage;
-            } else {
-                return null;
-            }
-        }
-
-        final Intent intent = new Intent(
-                RotationResolverService.SERVICE_INTERFACE).setPackage(resolvedPackage);
-
-        final ResolveInfo resolveInfo = context.getPackageManager().resolveServiceAsUser(intent,
-                flags, context.getUserId());
-        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
-            Slog.wtf(TAG, String.format("Service %s not found in package %s",
-                    RotationResolverService.SERVICE_INTERFACE, resolvedPackage));
-            return null;
-        }
-
-        final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-        final String permission = serviceInfo.permission;
-        if (Manifest.permission.BIND_ROTATION_RESOLVER_SERVICE.equals(permission)) {
-            Slog.i(TAG, String.format("Successfully bound the service from package: %s",
-                    resolvedPackage));
-            return serviceInfo.getComponentName();
-        }
-        Slog.e(TAG, String.format(
-                "Service %s should require %s permission. Found %s permission",
-                serviceInfo.getComponentName(),
-                Manifest.permission.BIND_ROTATION_RESOLVER_SERVICE,
-                serviceInfo.permission));
-        return null;
-    }
-
 
     /** Resolves and sets up the rotation resolver service if it had not been done yet. */
     @GuardedBy("mLock")
     @VisibleForTesting
     boolean isServiceAvailableLocked() {
         if (mComponentName == null) {
-            mComponentName = resolveRotationResolverService(getContext());
+            mComponentName = updateServiceInfoLocked();
         }
         return mComponentName != null;
     }
 
+    @Override // from PerUserSystemService
+    protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
+            throws PackageManager.NameNotFoundException {
+        ServiceInfo serviceInfo;
+        try {
+            serviceInfo = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+                    PackageManager.GET_META_DATA, mUserId);
+            if (serviceInfo != null) {
+                final String permission = serviceInfo.permission;
+                if (!Manifest.permission.BIND_ROTATION_RESOLVER_SERVICE.equals(permission)) {
+                    throw new SecurityException(String.format(
+                            "Service %s requires %s permission. Found %s permission",
+                            serviceInfo.getComponentName(),
+                            Manifest.permission.BIND_ROTATION_RESOLVER_SERVICE,
+                            serviceInfo.permission));
+                }
+            }
+        } catch (RemoteException e) {
+            throw new PackageManager.NameNotFoundException(
+                    "Could not get service for " + serviceComponent);
+        }
+        return serviceInfo;
+    }
 
     @GuardedBy("mLock")
     private void cancelLocked() {
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java b/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java
index a0e04ee..9f3f096 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java
@@ -23,7 +23,6 @@
 import android.os.ShellCommand;
 import android.rotationresolver.RotationResolverInternal.RotationResolverCallbackInternal;
 import android.service.rotationresolver.RotationResolutionRequest;
-import android.text.TextUtils;
 import android.view.Surface;
 
 import java.io.PrintWriter;
@@ -75,12 +74,10 @@
                 return runResolveRotation();
             case "get-last-resolution":
                 return getLastResolution();
-            case "set-testing-package":
-                return setTestRotationResolverPackage(getNextArgRequired());
             case "get-bound-package":
                 return getBoundPackageName();
-            case "clear-testing-package":
-                return resetTestRotationResolverPackage();
+            case "set-temporary-service":
+                return setTemporaryService(getNextArgRequired());
             default:
                 return handleDefaultCommands(cmd);
         }
@@ -93,17 +90,18 @@
         return 0;
     }
 
-    private int setTestRotationResolverPackage(String testingPackage) {
-        if (!TextUtils.isEmpty((testingPackage))) {
-            mService.setTestingPackage(testingPackage);
-            sTestableRotationCallbackInternal.reset();
+    private int setTemporaryService(String serviceName) {
+        final PrintWriter out = getOutPrintWriter();
+        if (serviceName == null) {
+            mService.getMaster().resetTemporaryService(mService.getUserId());
+            out.println("RotationResolverService temporary reset. ");
+            return 0;
         }
-        return 0;
-    }
 
-    private int resetTestRotationResolverPackage() {
-        mService.setTestingPackage("");
-        sTestableRotationCallbackInternal.reset();
+        final int duration = Integer.parseInt(getNextArgRequired());
+        mService.getMaster().setTemporaryService(mService.getUserId(), serviceName, duration);
+        out.println("RotationResolverService temporarily set to " + serviceName
+                + " for " + duration + "ms");
         return 0;
     }
 
@@ -130,8 +128,9 @@
         pw.println();
         pw.println("  resolve-rotation: request a rotation resolution.");
         pw.println("  get-last-resolution: show the last rotation resolution result.");
-        pw.println("  set-testing-package: Set the testing package that implements the service.");
         pw.println("  get-bound-package: print the bound package that implements the service.");
-        pw.println("  clear-testing-package: reset the testing package.");
+        pw.println("  set-temporary-service [COMPONENT_NAME DURATION]");
+        pw.println("    Temporarily (for DURATION ms) changes the service implementation.");
+        pw.println("    To reset, call with no argument.");
     }
 }
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 6f0741d..c1f8240 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -133,6 +133,7 @@
      * Throws a {@link SecurityException} iff the originator has permission to receive data.
      */
     void enforcePermissionsForDataDelivery(@NonNull Identity identity, @NonNull String reason) {
+        // TODO(b/186164881): remove
         // START TEMP HACK
         enforcePermissionForPreflight(mContext, identity, RECORD_AUDIO);
         int hotwordOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index e37edeb..d6e7574 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -71,6 +71,7 @@
 import com.android.internal.statusbar.RegisterStatusBarResult;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.GcUtils;
 import com.android.internal.view.AppearanceRegion;
 import com.android.server.LocalServices;
 import com.android.server.UiThread;
@@ -649,6 +650,7 @@
     // ================================================================================
     // From IStatusBarService
     // ================================================================================
+
     @Override
     public void expandNotificationsPanel() {
         enforceExpandStatusBar();
@@ -971,6 +973,22 @@
         return new int[] {disable1, disable2};
     }
 
+    void runGcForTest() {
+        if (!Build.IS_DEBUGGABLE) {
+            throw new SecurityException("runGcForTest requires a debuggable build");
+        }
+
+        // Gc the system along the way
+        GcUtils.runGcAndFinalizersSync();
+
+        if (mBar != null) {
+            try {
+                mBar.runGcForTest();
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
     @Override
     public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
             String contentDescription) {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
index 6171822..11a4976d 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java
@@ -75,6 +75,8 @@
                     return runSendDisableFlag();
                 case "tracing":
                     return runTracing();
+                case "run-gc":
+                    return runGc();
                 // Handle everything that would be handled in `handleDefaultCommand()` explicitly,
                 // so the default can be to pass all args to StatusBar
                 case "-h":
@@ -213,6 +215,11 @@
         return 0;
     }
 
+    private int runGc() {
+        mInterface.runGcForTest();
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         final PrintWriter pw = getOutPrintWriter();
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index e1747f7..f918827 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -50,6 +50,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.VcnManagementService.VcnCallback;
 import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import com.android.server.vcn.util.LogUtils;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -305,13 +306,13 @@
                 handleTeardown();
                 break;
             default:
-                Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
+                logWtf("Unknown msg.what: " + msg.what);
         }
     }
 
     private void handleConfigUpdated(@NonNull VcnConfig config) {
         // TODO: Add a dump function in VcnConfig that omits PII. Until then, use hashCode()
-        Slog.v(getLogTag(), "Config updated: config = " + config.hashCode());
+        logDbg("Config updated: old = " + mConfig.hashCode() + "; new = " + config.hashCode());
 
         mConfig = config;
 
@@ -326,8 +327,7 @@
             // connection details may have changed).
             if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
                 if (gatewayConnection == null) {
-                    Slog.wtf(
-                            getLogTag(), "Found gatewayConnectionConfig without GatewayConnection");
+                    logWtf("Found gatewayConnectionConfig without GatewayConnection");
                 } else {
                     gatewayConnection.teardownAsynchronously();
                 }
@@ -340,6 +340,7 @@
     }
 
     private void handleTeardown() {
+        logDbg("Tearing down");
         mVcnContext.getVcnNetworkProvider().unregisterListener(mRequestListener);
 
         for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
@@ -350,6 +351,7 @@
     }
 
     private void handleSafeModeStatusChanged() {
+        logDbg("VcnGatewayConnection safe mode status changed");
         boolean hasSafeModeGatewayConnection = false;
 
         // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode
@@ -365,21 +367,19 @@
                 hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
         if (oldStatus != mCurrentStatus) {
             mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection);
+            logDbg(
+                    "Safe mode "
+                            + (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited"));
         }
     }
 
     private void handleNetworkRequested(@NonNull NetworkRequest request) {
-        Slog.v(getLogTag(), "Received request " + request);
+        logVdbg("Received request " + request);
 
         // If preexisting VcnGatewayConnection(s) satisfy request, return
         for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) {
             if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
-                if (VDBG) {
-                    Slog.v(
-                            getLogTag(),
-                            "Request already satisfied by existing VcnGatewayConnection: "
-                                    + request);
-                }
+                logDbg("Request already satisfied by existing VcnGatewayConnection: " + request);
                 return;
             }
         }
@@ -389,7 +389,7 @@
         for (VcnGatewayConnectionConfig gatewayConnectionConfig :
                 mConfig.getGatewayConnectionConfigs()) {
             if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) {
-                Slog.v(getLogTag(), "Bringing up new VcnGatewayConnection for request " + request);
+                logDbg("Bringing up new VcnGatewayConnection for request " + request);
 
                 if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) {
                     // Skip; this network does not provide any services if mobile data is disabled.
@@ -400,8 +400,9 @@
                 // pre-existing VcnGatewayConnections that satisfy a given request, but if state
                 // that affects the satsifying of requests changes, this is theoretically possible.
                 if (mVcnGatewayConnections.containsKey(gatewayConnectionConfig)) {
-                    Slog.wtf(getLogTag(), "Attempted to bring up VcnGatewayConnection for config "
-                            + "with existing VcnGatewayConnection");
+                    logWtf(
+                            "Attempted to bring up VcnGatewayConnection for config "
+                                    + "with existing VcnGatewayConnection");
                     return;
                 }
 
@@ -414,8 +415,12 @@
                                 new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig),
                                 mIsMobileDataEnabled);
                 mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection);
+
+                return;
             }
         }
+
+        logVdbg("Request could not be fulfilled by VCN: " + request);
     }
 
     private Set<Integer> getExposedCapabilitiesForMobileDataState(
@@ -432,7 +437,7 @@
     }
 
     private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) {
-        Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config);
+        logDbg("VcnGatewayConnection quit: " + config);
         mVcnGatewayConnections.remove(config);
 
         // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
@@ -467,9 +472,7 @@
                 if (exposedCaps.contains(NET_CAPABILITY_INTERNET)
                         || exposedCaps.contains(NET_CAPABILITY_DUN)) {
                     if (gatewayConnection == null) {
-                        Slog.wtf(
-                                getLogTag(),
-                                "Found gatewayConnectionConfig without GatewayConnection");
+                        logWtf("Found gatewayConnectionConfig without" + " GatewayConnection");
                     } else {
                         // TODO(b/184868850): Optimize by restarting NetworkAgents without teardown.
                         gatewayConnection.teardownAsynchronously();
@@ -479,6 +482,8 @@
 
             // Trigger re-evaluation of all requests; mobile data state impacts supported caps.
             mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+
+            logDbg("Mobile data " + (mIsMobileDataEnabled ? "enabled" : "disabled"));
         }
     }
 
@@ -507,8 +512,38 @@
         return request.canBeSatisfiedBy(builder.build());
     }
 
-    private String getLogTag() {
-        return TAG + " [" + mSubscriptionGroup.hashCode() + "]";
+    private String getLogPrefix() {
+        return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "]: ";
+    }
+
+    private void logVdbg(String msg) {
+        if (VDBG) {
+            Slog.v(TAG, getLogPrefix() + msg);
+        }
+    }
+
+    private void logDbg(String msg) {
+        Slog.d(TAG, getLogPrefix() + msg);
+    }
+
+    private void logDbg(String msg, Throwable tr) {
+        Slog.d(TAG, getLogPrefix() + msg, tr);
+    }
+
+    private void logErr(String msg) {
+        Slog.e(TAG, getLogPrefix() + msg);
+    }
+
+    private void logErr(String msg, Throwable tr) {
+        Slog.e(TAG, getLogPrefix() + msg, tr);
+    }
+
+    private void logWtf(String msg) {
+        Slog.wtf(TAG, getLogPrefix() + msg);
+    }
+
+    private void logWtf(String msg, Throwable tr) {
+        Slog.wtf(TAG, getLogPrefix() + msg, tr);
     }
 
     /**
@@ -521,6 +556,7 @@
         pw.increaseIndent();
 
         pw.println("mCurrentStatus: " + mCurrentStatus);
+        pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled);
 
         pw.println("mVcnGatewayConnections:");
         for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) {
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 65b947c..5cecff6 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -88,6 +88,7 @@
 import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
 import com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkTrackerCallback;
 import com.android.server.vcn.Vcn.VcnGatewayStatusCallback;
+import com.android.server.vcn.util.LogUtils;
 import com.android.server.vcn.util.MtuUtils;
 
 import java.io.IOException;
@@ -701,6 +702,7 @@
      * <p>Once torn down, this VcnTunnel CANNOT be started again.
      */
     public void teardownAsynchronously() {
+        logDbg("Triggering async teardown");
         sendDisconnectRequestedAndAcquireWakelock(
                 DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */);
 
@@ -710,6 +712,8 @@
 
     @Override
     protected void onQuitting() {
+        logDbg("Quitting VcnGatewayConnection");
+
         // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down.
         if (mTunnelIface != null) {
             mTunnelIface.close();
@@ -750,6 +754,10 @@
             // TODO(b/180132994): explore safely removing this Thread check
             mVcnContext.ensureRunningOnLooperThread();
 
+            logDbg(
+                    "Selected underlying network changed: "
+                            + (underlying == null ? null : underlying.network));
+
             // TODO(b/179091925): Move the delayed-message handling to BaseState
 
             // If underlying is null, all underlying networks have been lost. Disconnect VCN after a
@@ -774,6 +782,8 @@
 
         if (!mIsQuitting) {
             mWakeLock.acquire();
+
+            logVdbg("Wakelock acquired: " + mWakeLock);
         }
     }
 
@@ -781,6 +791,8 @@
         mVcnContext.ensureRunningOnLooperThread();
 
         mWakeLock.release();
+
+        logVdbg("Wakelock released: " + mWakeLock);
     }
 
     /**
@@ -798,8 +810,7 @@
 
     @Override
     public void sendMessage(int what) {
-        Slog.wtf(
-                TAG,
+        logWtf(
                 "sendMessage should not be used in VcnGatewayConnection. See"
                         + " sendMessageAndAcquireWakeLock()");
         super.sendMessage(what);
@@ -807,8 +818,7 @@
 
     @Override
     public void sendMessage(int what, Object obj) {
-        Slog.wtf(
-                TAG,
+        logWtf(
                 "sendMessage should not be used in VcnGatewayConnection. See"
                         + " sendMessageAndAcquireWakeLock()");
         super.sendMessage(what, obj);
@@ -816,8 +826,7 @@
 
     @Override
     public void sendMessage(int what, int arg1) {
-        Slog.wtf(
-                TAG,
+        logWtf(
                 "sendMessage should not be used in VcnGatewayConnection. See"
                         + " sendMessageAndAcquireWakeLock()");
         super.sendMessage(what, arg1);
@@ -825,8 +834,7 @@
 
     @Override
     public void sendMessage(int what, int arg1, int arg2) {
-        Slog.wtf(
-                TAG,
+        logWtf(
                 "sendMessage should not be used in VcnGatewayConnection. See"
                         + " sendMessageAndAcquireWakeLock()");
         super.sendMessage(what, arg1, arg2);
@@ -834,8 +842,7 @@
 
     @Override
     public void sendMessage(int what, int arg1, int arg2, Object obj) {
-        Slog.wtf(
-                TAG,
+        logWtf(
                 "sendMessage should not be used in VcnGatewayConnection. See"
                         + " sendMessageAndAcquireWakeLock()");
         super.sendMessage(what, arg1, arg2, obj);
@@ -843,8 +850,7 @@
 
     @Override
     public void sendMessage(Message msg) {
-        Slog.wtf(
-                TAG,
+        logWtf(
                 "sendMessage should not be used in VcnGatewayConnection. See"
                         + " sendMessageAndAcquireWakeLock()");
         super.sendMessage(msg);
@@ -935,10 +941,14 @@
     }
 
     private void setTeardownTimeoutAlarm() {
+        logVdbg("Setting teardown timeout alarm; mCurrentToken: " + mCurrentToken);
+
         // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In
         // either case, there is nothing to cancel.
         if (mTeardownTimeoutAlarm != null) {
-            Slog.wtf(TAG, "mTeardownTimeoutAlarm should be null before being set");
+            logWtf(
+                    "mTeardownTimeoutAlarm should be null before being set; mCurrentToken: "
+                            + mCurrentToken);
         }
 
         final Message delayedMessage = obtainMessage(EVENT_TEARDOWN_TIMEOUT_EXPIRED, mCurrentToken);
@@ -950,6 +960,8 @@
     }
 
     private void cancelTeardownTimeoutAlarm() {
+        logVdbg("Cancelling teardown timeout alarm; mCurrentToken: " + mCurrentToken);
+
         if (mTeardownTimeoutAlarm != null) {
             mTeardownTimeoutAlarm.cancel();
             mTeardownTimeoutAlarm = null;
@@ -960,6 +972,11 @@
     }
 
     private void setDisconnectRequestAlarm() {
+        logVdbg(
+                "Setting alarm to disconnect due to underlying network loss;"
+                        + " mCurrentToken: "
+                        + mCurrentToken);
+
         // Only schedule a NEW alarm if none is already set.
         if (mDisconnectRequestAlarm != null) {
             return;
@@ -980,6 +997,11 @@
     }
 
     private void cancelDisconnectRequestAlarm() {
+        logVdbg(
+                "Cancelling alarm to disconnect due to underlying network loss;"
+                        + " mCurrentToken: "
+                        + mCurrentToken);
+
         if (mDisconnectRequestAlarm != null) {
             mDisconnectRequestAlarm.cancel();
             mDisconnectRequestAlarm = null;
@@ -993,10 +1015,14 @@
     }
 
     private void setRetryTimeoutAlarm(long delay) {
+        logVdbg("Setting retry alarm; mCurrentToken: " + mCurrentToken);
+
         // Safe to assign this alarm because it is either 1) already null, or 2) already fired. In
         // either case, there is nothing to cancel.
         if (mRetryTimeoutAlarm != null) {
-            Slog.wtf(TAG, "mRetryTimeoutAlarm should be null before being set");
+            logWtf(
+                    "mRetryTimeoutAlarm should be null before being set; mCurrentToken: "
+                            + mCurrentToken);
         }
 
         final Message delayedMessage = obtainMessage(EVENT_RETRY_TIMEOUT_EXPIRED, mCurrentToken);
@@ -1004,6 +1030,8 @@
     }
 
     private void cancelRetryTimeoutAlarm() {
+        logVdbg("Cancel retry alarm; mCurrentToken: " + mCurrentToken);
+
         if (mRetryTimeoutAlarm != null) {
             mRetryTimeoutAlarm.cancel();
             mRetryTimeoutAlarm = null;
@@ -1014,6 +1042,8 @@
 
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     void setSafeModeAlarm() {
+        logVdbg("Setting safe mode alarm; mCurrentToken: " + mCurrentToken);
+
         // Only schedule a NEW alarm if none is already set.
         if (mSafeModeTimeoutAlarm != null) {
             return;
@@ -1028,6 +1058,8 @@
     }
 
     private void cancelSafeModeAlarm() {
+        logVdbg("Cancel safe mode alarm; mCurrentToken: " + mCurrentToken);
+
         if (mSafeModeTimeoutAlarm != null) {
             mSafeModeTimeoutAlarm.cancel();
             mSafeModeTimeoutAlarm = null;
@@ -1092,6 +1124,14 @@
                             + exception.getMessage();
         }
 
+        logDbg(
+                "Encountered error; code="
+                        + errorCode
+                        + ", exceptionClass="
+                        + exceptionClass
+                        + ", exceptionMessage="
+                        + exceptionMessage);
+
         mGatewayStatusCallback.onGatewayConnectionError(
                 mConnectionConfig.getGatewayConnectionName(),
                 errorCode,
@@ -1137,7 +1177,7 @@
             try {
                 enterState();
             } catch (Exception e) {
-                Slog.wtf(TAG, "Uncaught exception", e);
+                logWtf("Uncaught exception", e);
                 sendDisconnectRequestedAndAcquireWakelock(
                         DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
             }
@@ -1169,14 +1209,14 @@
         public final boolean processMessage(Message msg) {
             final int token = msg.arg1;
             if (!isValidToken(token)) {
-                Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what);
+                logDbg("Message called with obsolete token: " + token + "; what: " + msg.what);
                 return HANDLED;
             }
 
             try {
                 processStateMsg(msg);
             } catch (Exception e) {
-                Slog.wtf(TAG, "Uncaught exception", e);
+                logWtf("Uncaught exception", e);
                 sendDisconnectRequestedAndAcquireWakelock(
                         DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
             }
@@ -1194,7 +1234,7 @@
             try {
                 exitState();
             } catch (Exception e) {
-                Slog.wtf(TAG, "Uncaught exception", e);
+                logWtf("Uncaught exception", e);
                 sendDisconnectRequestedAndAcquireWakelock(
                         DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */);
             }
@@ -1234,7 +1274,7 @@
         protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) {
             // TODO(b/180526152): notify VcnStatusCallback for Network loss
 
-            Slog.v(TAG, "Tearing down. Cause: " + info.reason);
+            logDbg("Tearing down. Cause: " + info.reason);
             mIsQuitting = info.shouldQuit;
 
             teardownNetwork();
@@ -1250,6 +1290,7 @@
 
         protected void handleSafeModeTimeoutExceeded() {
             mSafeModeTimeoutAlarm = null;
+            logDbg("Entering safe mode after timeout exceeded");
 
             // Connectivity for this GatewayConnection is broken; tear down the Network.
             teardownNetwork();
@@ -1258,13 +1299,15 @@
         }
 
         protected void logUnexpectedEvent(int what) {
-            Slog.d(TAG, String.format(
-                    "Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
+            logDbg(
+                    "Unexpected event code "
+                            + what
+                            + " in state "
+                            + this.getClass().getSimpleName());
         }
 
         protected void logWtfUnknownEvent(int what) {
-            Slog.wtf(TAG, String.format(
-                    "Unknown event code %d in state %s", what, this.getClass().getSimpleName()));
+            logWtf("Unknown event code " + what + " in state " + this.getClass().getSimpleName());
         }
     }
 
@@ -1281,7 +1324,7 @@
             }
 
             if (mIkeSession != null || mNetworkAgent != null) {
-                Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
+                logWtf("Active IKE Session or NetworkAgent in DisconnectedState");
             }
 
             cancelSafeModeAlarm();
@@ -1349,7 +1392,7 @@
         @Override
         protected void enterState() throws Exception {
             if (mIkeSession == null) {
-                Slog.wtf(TAG, "IKE session was already closed when entering Disconnecting state.");
+                logWtf("IKE session was already closed when entering Disconnecting state.");
                 sendMessageAndAcquireWakeLock(EVENT_SESSION_CLOSED, mCurrentToken);
                 return;
             }
@@ -1436,7 +1479,7 @@
         @Override
         protected void enterState() {
             if (mIkeSession != null) {
-                Slog.wtf(TAG, "ConnectingState entered with active session");
+                logWtf("ConnectingState entered with active session");
 
                 // Attempt to recover.
                 mIkeSession.kill();
@@ -1455,7 +1498,7 @@
 
                     if (oldUnderlying == null) {
                         // This should never happen, but if it does, there's likely a nasty bug.
-                        Slog.wtf(TAG, "Old underlying network was null in connected state. Bug?");
+                        logWtf("Old underlying network was null in connected state. Bug?");
                     }
 
                     // If new underlying is null, all underlying networks have been lost; disconnect
@@ -1550,11 +1593,11 @@
                                 // new NetworkAgent replaces an old one before the unwanted() call
                                 // is processed.
                                 if (mNetworkAgent != agentRef) {
-                                    Slog.d(TAG, "unwanted() called on stale NetworkAgent");
+                                    logDbg("unwanted() called on stale NetworkAgent");
                                     return;
                                 }
 
-                                Slog.d(TAG, "NetworkAgent was unwanted");
+                                logDbg("NetworkAgent was unwanted");
                                 teardownAsynchronously();
                             } /* networkUnwantedCallback */,
                             (status) -> {
@@ -1568,8 +1611,7 @@
                                         setSafeModeAlarm();
                                         break;
                                     default:
-                                        Slog.wtf(
-                                                TAG,
+                                        logWtf(
                                                 "Unknown validation status "
                                                         + status
                                                         + "; ignoring");
@@ -1602,13 +1644,26 @@
                 @NonNull Network underlyingNetwork,
                 @NonNull IpSecTransform transform,
                 int direction) {
+            if (direction != IpSecManager.DIRECTION_IN && direction != IpSecManager.DIRECTION_OUT) {
+                Slog.wtf(TAG, "Applying transform for unexpected direction: " + direction);
+            }
+
             try {
                 tunnelIface.setUnderlyingNetwork(underlyingNetwork);
 
                 // Transforms do not need to be persisted; the IkeSession will keep them alive
                 mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform);
+
+                // For inbound transforms, additionally allow forwarded traffic to bridge to DUN (as
+                // needed)
+                final Set<Integer> exposedCaps = mConnectionConfig.getAllExposedCapabilities();
+                if (direction == IpSecManager.DIRECTION_IN
+                        && exposedCaps.contains(NET_CAPABILITY_DUN)) {
+                    mIpSecManager.applyTunnelModeTransform(
+                            tunnelIface, IpSecManager.DIRECTION_FWD, transform);
+                }
             } catch (IOException e) {
-                Slog.d(TAG, "Transform application failed for network " + token, e);
+                logDbg("Transform application failed for network " + token, e);
                 sessionLost(token, e);
             }
         }
@@ -1642,7 +1697,7 @@
                     tunnelIface.removeAddress(address.getAddress(), address.getPrefixLength());
                 }
             } catch (IOException e) {
-                Slog.d(TAG, "Adding address to tunnel failed for token " + token, e);
+                logDbg("Adding address to tunnel failed for token " + token, e);
                 sessionLost(token, e);
             }
         }
@@ -1722,6 +1777,8 @@
         }
 
         private void handleMigrationCompleted(EventMigrationCompletedInfo migrationCompletedInfo) {
+            logDbg("Migration completed: " + mUnderlying.network);
+
             applyTransform(
                     mCurrentToken,
                     mTunnelIface,
@@ -1744,6 +1801,8 @@
             mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
 
             if (mUnderlying == null) {
+                logDbg("Underlying network lost");
+
                 // Ignored for now; a new network may be coming up. If none does, the delayed
                 // NETWORK_LOST disconnect will be fired, and tear down the session + network.
                 return;
@@ -1752,7 +1811,7 @@
             // mUnderlying assumed non-null, given check above.
             // If network changed, migrate. Otherwise, update any existing networkAgent.
             if (oldUnderlying == null || !oldUnderlying.network.equals(mUnderlying.network)) {
-                Slog.v(TAG, "Migrating to new network: " + mUnderlying.network);
+                logDbg("Migrating to new network: " + mUnderlying.network);
                 mIkeSession.setNetwork(mUnderlying.network);
             } else {
                 // oldUnderlying is non-null & underlying network itself has not changed
@@ -1803,7 +1862,7 @@
             mFailedAttempts++;
 
             if (mUnderlying == null) {
-                Slog.wtf(TAG, "Underlying network was null in retry state");
+                logWtf("Underlying network was null in retry state");
                 transitionTo(mDisconnectedState);
             } else {
                 // Safe to blindly set up, as it is cancelled and cleared on exiting this state
@@ -1973,25 +2032,25 @@
 
         @Override
         public void onOpened(@NonNull IkeSessionConfiguration ikeSessionConfig) {
-            Slog.v(TAG, "IkeOpened for token " + mToken);
+            logDbg("IkeOpened for token " + mToken);
             // Nothing to do here.
         }
 
         @Override
         public void onClosed() {
-            Slog.v(TAG, "IkeClosed for token " + mToken);
+            logDbg("IkeClosed for token " + mToken);
             sessionClosed(mToken, null);
         }
 
         @Override
         public void onClosedExceptionally(@NonNull IkeException exception) {
-            Slog.v(TAG, "IkeClosedExceptionally for token " + mToken, exception);
+            logDbg("IkeClosedExceptionally for token " + mToken, exception);
             sessionClosed(mToken, exception);
         }
 
         @Override
         public void onError(@NonNull IkeProtocolException exception) {
-            Slog.v(TAG, "IkeError for token " + mToken, exception);
+            logDbg("IkeError for token " + mToken, exception);
             // Non-fatal, log and continue.
         }
     }
@@ -2008,7 +2067,7 @@
         /** Internal proxy method for injecting of mocked ChildSessionConfiguration */
         @VisibleForTesting(visibility = Visibility.PRIVATE)
         void onOpened(@NonNull VcnChildSessionConfiguration childConfig) {
-            Slog.v(TAG, "ChildOpened for token " + mToken);
+            logDbg("ChildOpened for token " + mToken);
             childOpened(mToken, childConfig);
         }
 
@@ -2019,19 +2078,19 @@
 
         @Override
         public void onClosed() {
-            Slog.v(TAG, "ChildClosed for token " + mToken);
+            logDbg("ChildClosed for token " + mToken);
             sessionLost(mToken, null);
         }
 
         @Override
         public void onClosedExceptionally(@NonNull IkeException exception) {
-            Slog.v(TAG, "ChildClosedExceptionally for token " + mToken, exception);
+            logDbg("ChildClosedExceptionally for token " + mToken, exception);
             sessionLost(mToken, exception);
         }
 
         @Override
         public void onIpSecTransformCreated(@NonNull IpSecTransform transform, int direction) {
-            Slog.v(TAG, "ChildTransformCreated; Direction: " + direction + "; token " + mToken);
+            logDbg("ChildTransformCreated; Direction: " + direction + "; token " + mToken);
             childTransformCreated(mToken, transform, direction);
         }
 
@@ -2039,7 +2098,7 @@
         public void onIpSecTransformsMigrated(
                 @NonNull IpSecTransform inIpSecTransform,
                 @NonNull IpSecTransform outIpSecTransform) {
-            Slog.v(TAG, "ChildTransformsMigrated; token " + mToken);
+            logDbg("ChildTransformsMigrated; token " + mToken);
             migrationCompleted(mToken, inIpSecTransform, outIpSecTransform);
         }
 
@@ -2047,10 +2106,48 @@
         public void onIpSecTransformDeleted(@NonNull IpSecTransform transform, int direction) {
             // Nothing to be done; no references to the IpSecTransform are held, and this transform
             // will be closed by the IKE library.
-            Slog.v(TAG, "ChildTransformDeleted; Direction: " + direction + "; for token " + mToken);
+            logDbg("ChildTransformDeleted; Direction: " + direction + "; for token " + mToken);
         }
     }
 
+    private String getLogPrefix() {
+        return "["
+                + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup)
+                + "-"
+                + mConnectionConfig.getGatewayConnectionName()
+                + "]: ";
+    }
+
+    private void logVdbg(String msg) {
+        if (VDBG) {
+            Slog.v(TAG, getLogPrefix() + msg);
+        }
+    }
+
+    private void logDbg(String msg) {
+        Slog.d(TAG, getLogPrefix() + msg);
+    }
+
+    private void logDbg(String msg, Throwable tr) {
+        Slog.d(TAG, getLogPrefix() + msg, tr);
+    }
+
+    private void logErr(String msg) {
+        Slog.e(TAG, getLogPrefix() + msg);
+    }
+
+    private void logErr(String msg, Throwable tr) {
+        Slog.e(TAG, getLogPrefix() + msg, tr);
+    }
+
+    private void logWtf(String msg) {
+        Slog.wtf(TAG, getLogPrefix() + msg);
+    }
+
+    private void logWtf(String msg, Throwable tr) {
+        Slog.wtf(TAG, getLogPrefix() + msg, tr);
+    }
+
     /**
      * Dumps the state of this VcnGatewayConnection for logging and debugging purposes.
      *
diff --git a/services/core/java/com/android/server/vcn/util/LogUtils.java b/services/core/java/com/android/server/vcn/util/LogUtils.java
new file mode 100644
index 0000000..93728ce
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/util/LogUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn.util;
+
+import android.annotation.Nullable;
+import android.os.ParcelUuid;
+
+import com.android.internal.util.HexDump;
+
+/** @hide */
+public class LogUtils {
+    /**
+     * Returns the hash of the subscription group in hexadecimal format.
+     *
+     * @return the hexadecimal encoded string if uuid was non-null, else {@code null}
+     */
+    @Nullable
+    public static String getHashedSubscriptionGroup(@Nullable ParcelUuid uuid) {
+        if (uuid == null) {
+            return null;
+        }
+
+        return HexDump.toHexString(uuid.hashCode());
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8f3702a..9f51d97 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -115,8 +115,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_UNSET;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
@@ -325,7 +323,6 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.XmlUtils;
-import com.android.internal.util.function.pooled.PooledConsumer;
 import com.android.internal.util.function.pooled.PooledFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
@@ -2385,7 +2382,8 @@
         return occludesParent(false /* includingFinishing */);
     }
 
-    private boolean occludesParent(boolean includingFinishing) {
+    @VisibleForTesting
+    boolean occludesParent(boolean includingFinishing) {
         if (!includingFinishing && finishing) {
             return false;
         }
@@ -2843,7 +2841,6 @@
 
             final boolean endTask = task.getTopNonFinishingActivity() == null
                     && !task.isClearingToReuseTask();
-            final int transit = endTask ? TRANSIT_OLD_TASK_CLOSE : TRANSIT_OLD_ACTIVITY_CLOSE;
             if (newTransition != null) {
                 mAtmService.getTransitionController().requestStartTransition(newTransition,
                         endTask ? task : null, null /* remote */);
@@ -2900,7 +2897,7 @@
             } else if (!isState(PAUSING)) {
                 if (mVisibleRequested) {
                     // Prepare and execute close transition.
-                    prepareActivityHideTransitionAnimation(transit);
+                    prepareActivityHideTransitionAnimation();
                 }
 
                 final boolean removedActivity = completeFinishing("finishIfPossible") == null;
@@ -2918,11 +2915,9 @@
                 // In this case, we can set the visibility of all the task overlay activities when
                 // we detect the last one is finishing to keep them in sync.
                 if (task.onlyHasTaskOverlayActivities(false /* includeFinishing */)) {
-                    final PooledConsumer c = PooledLambda.obtainConsumer(
-                            ActivityRecord::prepareActivityHideTransitionAnimationIfOvarlay,
-                            PooledLambda.__(ActivityRecord.class), transit);
-                    task.forAllActivities(c);
-                    c.recycle();
+                    task.forAllActivities((r) -> {
+                        r.prepareActivityHideTransitionAnimationIfOvarlay();
+                    });
                 }
                 return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED;
             } else {
@@ -2935,28 +2930,33 @@
         }
     }
 
-    private void prepareActivityHideTransitionAnimationIfOvarlay(@TransitionOldType int transit) {
+    private void prepareActivityHideTransitionAnimationIfOvarlay() {
         if (mTaskOverlay) {
-            prepareActivityHideTransitionAnimation(transit);
+            prepareActivityHideTransitionAnimation();
         }
     }
 
-    private void prepareActivityHideTransitionAnimation(@TransitionOldType int transit) {
+    private void prepareActivityHideTransitionAnimation() {
         final DisplayContent dc = mDisplayContent;
         dc.prepareAppTransition(TRANSIT_CLOSE);
         setVisibility(false);
         dc.executeAppTransition();
     }
 
+    ActivityRecord completeFinishing(String reason) {
+        return completeFinishing(true /* updateVisibility */, reason);
+    }
+
     /**
      * Complete activity finish request that was initiated earlier. If the activity is still
      * pausing we will wait for it to complete its transition. If the activity that should appear in
      * place of this one is not visible yet - we'll wait for it first. Otherwise - activity can be
      * destroyed right away.
+     * @param updateVisibility Indicate if need to update activity visibility.
      * @param reason Reason for finishing the activity.
      * @return Flag indicating whether the activity was removed from history.
      */
-    ActivityRecord completeFinishing(String reason) {
+    ActivityRecord completeFinishing(boolean updateVisibility, String reason) {
         if (!finishing || isState(RESUMED)) {
             throw new IllegalArgumentException(
                     "Activity must be finishing and not resumed to complete, r=" + this
@@ -2968,13 +2968,11 @@
             return this;
         }
 
-        final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED);
-        if (isCurrentVisible) {
-            final Task rootTask = getRootTask();
-            final ActivityRecord activity = rootTask.getResumedActivity();
+        final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED, STARTED);
+        if (updateVisibility && isCurrentVisible) {
             boolean ensureVisibility = false;
-            if (activity != null && !activity.occludesParent()) {
-                // If the resume activity is not opaque, we need to make sure the visibilities of
+            if (occludesParent(true /* includingFinishing */)) {
+                // If the current activity is not opaque, we need to make sure the visibilities of
                 // activities be updated, they may be seen by users.
                 ensureVisibility = true;
             } else if (mTaskSupervisor.getKeyguardController().isKeyguardLocked()
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index eeb7fac..47622bc 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -74,8 +74,8 @@
      */
     public abstract void addWindow(WindowToken token);
 
-    /** Gets the {@link DisplayArea} which a {@link WindowToken} is about to be attached to. */
-    public abstract DisplayArea.Tokens getDisplayAreaForWindowToken(int type, Bundle options,
+    /** Gets the {@link DisplayArea} with given window type and launched options */
+    public abstract DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
             boolean ownerCanManageAppTokens, boolean roundedCornerOverlay);
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index a7312b3..47d7c9d 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -756,7 +756,14 @@
         @VisibleForTesting
         DisplayArea.Tokens findAreaForToken(WindowToken token) {
             return mSelectRootForWindowFunc.apply(token.windowType, token.mOptions)
-                    .findAreaForToken(token);
+                    .findAreaForTokenInLayer(token);
+        }
+
+        @Override
+        public DisplayArea.Tokens findAreaForWindowType(int type, Bundle options,
+                boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
+            return mSelectRootForWindowFunc.apply(type, options).findAreaForWindowTypeInLayer(type,
+                    ownerCanManageAppTokens, roundedCornerOverlay);
         }
 
         @VisibleForTesting
@@ -794,13 +801,6 @@
         public TaskDisplayArea getDefaultTaskDisplayArea() {
             return mDefaultTaskDisplayArea;
         }
-
-        @Override
-        public DisplayArea.Tokens getDisplayAreaForWindowToken(int type, Bundle options,
-                boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
-            return mSelectRootForWindowFunc.apply(type, options).findAreaForToken(type,
-                    ownerCanManageAppTokens, roundedCornerOverlay);
-        }
     }
 
     static class PendingArea {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a108478..8800a9e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1123,15 +1123,8 @@
             token.mDisplayContent = this;
             // Add non-app token to container hierarchy on the display. App tokens are added through
             // the parent container managing them (e.g. Tasks).
-            switch (token.windowType) {
-                case TYPE_INPUT_METHOD:
-                case TYPE_INPUT_METHOD_DIALOG:
-                    mImeWindowsContainer.addChild(token);
-                    break;
-                default:
-                    mDisplayAreaPolicy.addWindow(token);
-                    break;
-            }
+            final DisplayArea.Tokens da = findAreaForToken(token).asTokens();
+            da.addChild(token);
         }
     }
 
@@ -1569,6 +1562,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.
+            return false;
+        }
         final int rotation = rotationForActivityInDifferentOrientation(r);
         if (rotation == ROTATION_UNDEFINED) {
             // The display rotation won't be changed by current top activity. The client side
@@ -2456,6 +2453,10 @@
         setWindowingMode(windowingMode);
     }
 
+    /**
+     * See {@code WindowState#applyImeWindowsIfNeeded} for the details that we won't traverse the
+     * IME window in some cases.
+     */
     boolean forAllImeWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
         return mImeWindowsContainer.forAllWindowForce(callback, traverseTopToBottom);
     }
@@ -4573,6 +4574,8 @@
         private boolean skipImeWindowsDuringTraversal(DisplayContent dc) {
             // We skip IME windows so they're processed just above their target, except
             // in split-screen mode where we process the IME containers above the docked divider.
+            // Note that this method check should align with {@link
+            // WindowState#applyImeWindowsIfNeeded} in case of any state mismatch.
             return dc.getImeTarget(IME_TARGET_LAYERING) != null
                     && !dc.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
         }
@@ -5982,7 +5985,7 @@
         return mMagnificationSpec;
     }
 
-    DisplayArea getAreaForWindowToken(int windowType, Bundle options,
+    DisplayArea findAreaForWindowType(int windowType, Bundle options,
             boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
         // TODO(b/159767464): figure out how to find an appropriate TDA.
         if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
@@ -5994,10 +5997,28 @@
         if (windowType == TYPE_INPUT_METHOD || windowType == TYPE_INPUT_METHOD_DIALOG) {
             return getImeContainer();
         }
-        return mDisplayAreaPolicy.getDisplayAreaForWindowToken(windowType, options,
+        return mDisplayAreaPolicy.findAreaForWindowType(windowType, options,
                 ownerCanManageAppToken, roundedCornerOverlay);
     }
 
+    /**
+     * Finds the {@link DisplayArea} for the {@link WindowToken} to attach to.
+     * <p>
+     * Note that the differences between this API and
+     * {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} is that this API finds a
+     * {@link DisplayArea} in {@link DisplayContent} level, which may find a {@link DisplayArea}
+     * from multiple {@link RootDisplayArea RootDisplayAreas} under this {@link DisplayContent}'s
+     * hierarchy, while {@link RootDisplayArea#findAreaForTokenInLayer(WindowToken)} finds a
+     * {@link DisplayArea.Tokens} from a {@link DisplayArea.Tokens} list mapped to window layers.
+     * </p>
+     *
+     * @see DisplayContent#findAreaForTokenInLayer(WindowToken)
+     */
+    DisplayArea findAreaForToken(WindowToken windowToken) {
+        return findAreaForWindowType(windowToken.getWindowType(), windowToken.mOptions,
+                windowToken.mOwnerCanManageAppTokens, windowToken.mRoundedCornerOverlay);
+    }
+
     @Override
     DisplayContent asDisplayContent() {
         return this;
diff --git a/services/core/java/com/android/server/wm/PinnedTaskController.java b/services/core/java/com/android/server/wm/PinnedTaskController.java
index dea83f0..7b4b23e 100644
--- a/services/core/java/com/android/server/wm/PinnedTaskController.java
+++ b/services/core/java/com/android/server/wm/PinnedTaskController.java
@@ -257,15 +257,16 @@
             // be rotated.
             float dx = pipTx.mPositionX;
             float dy = pipTx.mPositionY;
+            final Matrix matrix = pipTx.getMatrix();
             if (pipTx.mRotation == 90) {
                 dx = pipTx.mPositionY;
                 dy = areaBounds.right - pipTx.mPositionX;
+                matrix.postRotate(-90);
             } else if (pipTx.mRotation == -90) {
                 dx = areaBounds.bottom - pipTx.mPositionY;
                 dy = pipTx.mPositionX;
+                matrix.postRotate(90);
             }
-            final Matrix matrix = new Matrix();
-            matrix.setScale(pipTx.mScaleX, pipTx.mScaleY);
             matrix.postTranslate(dx, dy);
             t.setMatrix(pinnedTask.getSurfaceControl(), matrix, new float[9]);
             Slog.i(TAG, "Seamless rotation PiP tx=" + pipTx + " pos=" + dx + "," + dy);
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index 1cda8d5..d94bb9e 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -101,15 +101,24 @@
                 "There is no FEATURE_IME_PLACEHOLDER in this root to place the IME container");
     }
 
-    /** Finds the {@link DisplayArea.Tokens} that this type of window should be attached to. */
+    /**
+     * Finds the {@link DisplayArea.Tokens} in {@code mAreaForLayer} that this type of window
+     * should be attached to.
+     * <p>
+     * Note that in most cases, users are expected to call
+     * {@link DisplayContent#findAreaForToken(WindowToken)} to find a {@link DisplayArea} in
+     * {@link DisplayContent} level instead of calling this inner method.
+     * </p>
+     */
     @Nullable
-    DisplayArea.Tokens findAreaForToken(WindowToken token) {
-        return findAreaForToken(token.windowType, token.mOwnerCanManageAppTokens,
+    DisplayArea.Tokens findAreaForTokenInLayer(WindowToken token) {
+        return findAreaForWindowTypeInLayer(token.windowType, token.mOwnerCanManageAppTokens,
                 token.mRoundedCornerOverlay);
     }
 
+    /** @see #findAreaForTokenInLayer(WindowToken)  */
     @Nullable
-    DisplayArea.Tokens findAreaForToken(int windowType, boolean ownerCanManageAppTokens,
+    DisplayArea.Tokens findAreaForWindowTypeInLayer(int windowType, boolean ownerCanManageAppTokens,
             boolean roundedCornerOverlay) {
         int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType,
                 ownerCanManageAppTokens, roundedCornerOverlay);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e5e1a7a..be01173 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5842,8 +5842,13 @@
             final boolean wasStopping = prev.isState(STOPPING);
             prev.setState(PAUSED, "completePausedLocked");
             if (prev.finishing) {
+                // We will update the activity visibility later, no need to do in
+                // completeFinishing(). Updating visibility here might also making the next
+                // activities to be resumed, and could result in wrong app transition due to
+                // lack of previous activity information.
                 ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev);
-                prev = prev.completeFinishing("completePausedLocked");
+                prev = prev.completeFinishing(false /* updateVisibility */,
+                        "completePausedLocked");
             } else if (prev.hasProcess()) {
                 ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
                         + "wasStopping=%b visibleRequested=%b",  prev,  wasStopping,
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index fb481b4..a4c8db6 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -38,6 +38,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
@@ -75,6 +76,9 @@
     private static final int REPORT_CONFIGS = CONTROLLABLE_CONFIGS;
     private static final int REPORT_WINDOW_CONFIGS = CONTROLLABLE_WINDOW_CONFIGS;
 
+    private static final boolean DEBUG_ENABLE_REVEAL_ANIMATION =
+            SystemProperties.getBoolean("persist.debug.enable_reveal_animation", false);
+
     // The set of modes that are currently supports
     // TODO: Remove once the task organizer can support all modes
     @VisibleForTesting
@@ -183,7 +187,7 @@
             SurfaceControl windowAnimationLeash = null;
             Rect mainFrame = null;
             final boolean playShiftUpAnimation = !task.inMultiWindowMode();
-            if (prepareAnimation && playShiftUpAnimation) {
+            if (prepareAnimation && playShiftUpAnimation && DEBUG_ENABLE_REVEAL_ANIMATION) {
                 final ActivityRecord topActivity = task.topActivityWithStartingWindow();
                 if (topActivity != null) {
                     final WindowState mainWindow =
diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java
index b417832..bc53041 100644
--- a/services/core/java/com/android/server/wm/WindowContextListenerController.java
+++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java
@@ -201,7 +201,9 @@
             return mContainer;
         }
 
-        private void updateContainer(WindowContainer newContainer) {
+        private void updateContainer(@NonNull WindowContainer newContainer) {
+            Objects.requireNonNull(newContainer);
+
             if (mContainer.equals(newContainer)) {
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d43a763..ab5e498 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2688,7 +2688,7 @@
                 }
                 // TODO(b/155340867): Investigate if we still need roundedCornerOverlay after
                 // the feature b/155340867 is completed.
-                final DisplayArea da = dc.getAreaForWindowToken(type, options,
+                final DisplayArea da = dc.findAreaForWindowType(type, options,
                         callerCanManageAppTokens, false /* roundedCornerOverlay */);
                 mWindowContextListenerController.registerWindowContainerListener(clientToken, da,
                         callingUid, type, options);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b40223f..540035f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4842,7 +4842,10 @@
         // directly above it. The exception is if we are in split screen
         // in which case we process the IME at the DisplayContent level to
         // ensure it is above the docked divider.
-        if (isImeLayeringTarget() && !inSplitScreenWindowingMode()) {
+        // (i.e. Like {@link DisplayContent.ImeContainer#skipImeWindowsDuringTraversal}, the IME
+        // window will be ignored to traverse when the IME target is still in split-screen mode).
+        if (isImeLayeringTarget()
+                && !getDisplayContent().getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
             if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) {
                 return true;
             }
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 6721ecf..bfd8005 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -66,7 +66,7 @@
 
     android::sp<IStats> statsHal = new StatsHal();
     const android::status_t err = statsHal->registerAsService();
-    LOG_ALWAYS_FATAL_IF(err != android::OK, "Cannot register HIDL %s: %d", IStats::descriptor, err);
+    ALOGW_IF(err != android::OK, "Cannot register HIDL %s: %d", IStats::descriptor, err);
 }
 
 } // namespace
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ef7360d..23a67b7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -28,6 +28,7 @@
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
+import static android.app.admin.DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED;
 import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY;
 import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE;
 import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED;
@@ -883,12 +884,6 @@
                 synchronized (getLockObject()) {
                     // Check whether the user is affiliated, *before* removing its data.
                     boolean isRemovedUserAffiliated = isUserAffiliatedWithDeviceLocked(userHandle);
-                    if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) {
-                        // Disable network and security logging
-                        mInjector.securityLogSetLoggingEnabledProperty(false);
-                        mSecurityLogMonitor.stop();
-                        setNetworkLoggingActiveInternal(false);
-                    }
                     removeUserData(userHandle);
                     if (!isRemovedUserAffiliated) {
                         // We discard the logs when unaffiliated users are deleted (so that the
@@ -1779,6 +1774,7 @@
     }
 
     void removeUserData(int userHandle) {
+        final boolean isOrgOwned;
         synchronized (getLockObject()) {
             if (userHandle == UserHandle.USER_SYSTEM) {
                 Slogf.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
@@ -1786,6 +1782,9 @@
             }
             updatePasswordQualityCacheForUserGroup(userHandle);
             mPolicyCache.onUserRemoved(userHandle);
+
+            isOrgOwned = mOwners.isProfileOwnerOfOrganizationOwnedDevice(userHandle);
+
             mOwners.removeProfileOwner(userHandle);
             mOwners.writeProfileOwner(userHandle);
 
@@ -1799,6 +1798,14 @@
             policyFile.delete();
             Slogf.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
         }
+        if (isOrgOwned) {
+            final UserInfo primaryUser = mUserManager.getPrimaryUser();
+            if (primaryUser != null) {
+                clearOrgOwnedProfileOwnerDeviceWidePolicies(primaryUser.id);
+            } else {
+                Slogf.wtf(LOG_TAG, "Was unable to get primary user.");
+            }
+        }
     }
 
     /**
@@ -3537,6 +3544,7 @@
                 "Caller must be shell or hold MANAGE_PROFILE_AND_DEVICE_OWNERS to call "
                         + "forceRemoveActiveAdmin");
         mInjector.binderWithCleanCallingIdentity(() -> {
+            boolean isOrgOwnedProfile = false;
             synchronized (getLockObject()) {
                 if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) {
                     throw new SecurityException("Attempt to remove non-test admin "
@@ -3548,13 +3556,7 @@
                     clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle);
                 }
                 if (isProfileOwner(adminReceiver, userHandle)) {
-                    if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) {
-                        UserHandle parentUserHandle = UserHandle.of(getProfileParentId(userHandle));
-                        mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
-                                false, parentUserHandle);
-                        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER,
-                                false, parentUserHandle);
-                    }
+                    isOrgOwnedProfile = isProfileOwnerOfOrganizationOwnedDevice(userHandle);
                     final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver,
                             userHandle, /* parent */ false);
                     clearProfileOwnerLocked(admin, userHandle);
@@ -3562,11 +3564,26 @@
             }
             // Remove the admin skipping sending the broadcast.
             removeAdminArtifacts(adminReceiver, userHandle);
+
+            // In case of PO on org owned device, clean device-wide policies and restrictions.
+            if (isOrgOwnedProfile) {
+                final UserHandle parentUser = UserHandle.of(getProfileParentId(userHandle));
+                clearOrgOwnedProfileOwnerUserRestrictions(parentUser);
+                clearOrgOwnedProfileOwnerDeviceWidePolicies(parentUser.getIdentifier());
+            }
+
             Slogf.i(LOG_TAG, "Admin " + adminReceiver + " removed from user " + userHandle);
         });
     }
 
-    private void clearDeviceOwnerUserRestrictionLocked(UserHandle userHandle) {
+    private void clearOrgOwnedProfileOwnerUserRestrictions(UserHandle parentUserHandle) {
+        mUserManager.setUserRestriction(
+                UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, parentUserHandle);
+        mUserManager.setUserRestriction(
+                UserManager.DISALLOW_ADD_USER, false, parentUserHandle);
+    }
+
+    private void clearDeviceOwnerUserRestriction(UserHandle userHandle) {
         // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state
         if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_USER, userHandle)) {
             mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false, userHandle);
@@ -6710,25 +6727,16 @@
                 // when wipeData is _not_ called on the parent instance, it implies relinquishing
                 // control over the device, wiping only the work profile. So the user restriction
                 // on profile removal needs to be removed first.
-
-                mInjector.binderWithCleanCallingIdentity(() -> {
-                    // Clear restriction as user.
-                    mUserManager.setUserRestriction(
-                            UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false,
-                            UserHandle.SYSTEM);
-                    mUserManager.setUserRestriction(
-                            UserManager.DISALLOW_ADD_USER, false, UserHandle.SYSTEM);
-
-                    // Device-wide policies set by the profile owner need to be cleaned up here.
-                    mLockPatternUtils.setDeviceOwnerInfo(null);
-                });
+                final UserHandle parentUser = UserHandle.of(getProfileParentId(userId));
+                mInjector.binderWithCleanCallingIdentity(
+                        () -> clearOrgOwnedProfileOwnerUserRestrictions(parentUser));
             }
         }
         DevicePolicyEventLogger event = DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.WIPE_DATA_WITH_REASON)
                 .setInt(flags)
-                .setStrings(calledOnParentInstance ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
-                ;
+                .setStrings(calledOnParentInstance ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT);
+
         final String adminName;
         final ComponentName adminComp;
         if (admin != null) {
@@ -6755,6 +6763,55 @@
         wipeDataNoLock(adminComp, flags, internalReason, wipeReasonForUser, userId);
     }
 
+    /**
+     * Clears device wide policies enforced by COPE PO when relinquishing the device. This method
+     * should be invoked once the admin is gone, so that all methods that rely on calculating
+     * aggregate policy (e.g. strong auth timeout) from all admins aren't affected by its policies.
+     * This method assumes that there is no other device or profile owners left on the device.
+     * Shouldn't be called from binder thread without clearing identity.
+     */
+    private void clearOrgOwnedProfileOwnerDeviceWidePolicies(@UserIdInt int parentId) {
+        Slogf.i(LOG_TAG, "Cleaning up device-wide policies left over from org-owned profile...");
+        // Lockscreen message
+        mLockPatternUtils.setDeviceOwnerInfo(null);
+        // Wifi config lockdown
+        mInjector.settingsGlobalPutInt(Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0);
+        // Security logging
+        if (mInjector.securityLogGetLoggingEnabledProperty()) {
+            mSecurityLogMonitor.stop();
+            mInjector.securityLogSetLoggingEnabledProperty(false);
+        }
+        // Network logging
+        setNetworkLoggingActiveInternal(false);
+
+        // System update policy.
+        final boolean hasSystemUpdatePolicy;
+        synchronized (getLockObject()) {
+            hasSystemUpdatePolicy = mOwners.getSystemUpdatePolicy() != null;
+            if (hasSystemUpdatePolicy) {
+                mOwners.clearSystemUpdatePolicy();
+                mOwners.writeDeviceOwner();
+            }
+        }
+        if (hasSystemUpdatePolicy) {
+            mContext.sendBroadcastAsUser(
+                    new Intent(ACTION_SYSTEM_UPDATE_POLICY_CHANGED), UserHandle.SYSTEM);
+        }
+
+        // Unsuspend personal apps if needed.
+        suspendPersonalAppsInternal(parentId, false);
+
+        // Notify FRP agent, LSS and WindowManager to ensure they don't hold on to stale policies.
+        final int frpAgentUid = getFrpManagementAgentUid();
+        if (frpAgentUid > 0) {
+            notifyResetProtectionPolicyChanged(frpAgentUid);
+        }
+        mLockSettingsInternal.refreshStrongAuthTimeout(parentId);
+        updateScreenCaptureDisabled(parentId, getScreenCaptureDisabled(null, parentId, false));
+
+        Slogf.i(LOG_TAG, "Cleaning up device-wide policies done.");
+    }
+
     private void wipeDataNoLock(ComponentName admin, int flags, String internalReason,
                                 String wipeReasonForUser, int userId) {
         wtfIfInLock();
@@ -6822,13 +6879,8 @@
             saveSettingsLocked(caller.getUserId());
         }
 
-        final Intent intent = new Intent(
-                DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED).addFlags(
-                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND);
-
-        mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser(intent,
-                UserHandle.getUserHandleForUid(frpManagementAgentUid),
-                android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION));
+        mInjector.binderWithCleanCallingIdentity(
+                () -> notifyResetProtectionPolicyChanged(frpManagementAgentUid));
 
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_FACTORY_RESET_PROTECTION)
@@ -6836,6 +6888,16 @@
                 .write();
     }
 
+    // Shouldn't be called from binder thread without clearing identity.
+    private void notifyResetProtectionPolicyChanged(int frpManagementAgentUid) {
+        final Intent intent = new Intent(
+                DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED).addFlags(
+                Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_FOREGROUND);
+        mContext.sendBroadcastAsUser(intent,
+                UserHandle.getUserHandleForUid(frpManagementAgentUid),
+                permission.MANAGE_FACTORY_RESET_PROTECTION);
+    }
+
     @Override
     public FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(
             @Nullable ComponentName who) {
@@ -8506,7 +8568,7 @@
         mOwners.writeDeviceOwner();
         updateDeviceOwnerLocked();
 
-        clearDeviceOwnerUserRestrictionLocked(UserHandle.of(userId));
+        clearDeviceOwnerUserRestriction(UserHandle.of(userId));
         mInjector.securityLogSetLoggingEnabledProperty(false);
         mSecurityLogMonitor.stop();
         setNetworkLoggingActiveInternal(false);
@@ -12936,8 +12998,7 @@
             mOwners.writeDeviceOwner();
         }
         mInjector.binderWithCleanCallingIdentity(() -> mContext.sendBroadcastAsUser(
-                new Intent(DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED),
-                UserHandle.SYSTEM));
+                new Intent(ACTION_SYSTEM_UPDATE_POLICY_CHANGED), UserHandle.SYSTEM));
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_SYSTEM_UPDATE_POLICY)
                 .setAdmin(who)
@@ -14513,14 +14574,10 @@
      * apps.
      */
     @Override
-    public void forceUpdateUserSetupComplete() {
-        final CallerIdentity caller = getCallerIdentity();
+    public void forceUpdateUserSetupComplete(@UserIdInt int userId) {
         Preconditions.checkCallAuthorization(
                 hasCallingOrSelfPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
-        Preconditions.checkCallAuthorization(caller.getUserHandle().isSystem(),
-                "Caller has to be in user 0");
 
-        final int userId = UserHandle.USER_SYSTEM;
         boolean isUserCompleted = mInjector.settingsSecureGetIntForUser(
                 Settings.Secure.USER_SETUP_COMPLETE, 0, userId) != 0;
         DevicePolicyData policy = getUserData(userId);
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 51b270c..24699d9 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -983,7 +983,8 @@
     bool enableReadTimeouts = ifs.readTimeoutsRequested();
 
     std::lock_guard l(mMountOperationLock);
-    auto status = mVold->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts);
+    auto status = mVold->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts,
+                                              ifs.metricsKey);
     if (status.isOk()) {
         // Store states.
         ifs.setReadLogsEnabled(enableReadLogs);
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 68a28b2..ce3d514 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -56,8 +56,10 @@
     }
     binder::Status setIncFsMountOptions(
             const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
-            bool enableReadLogs, bool enableReadTimeouts) const final {
-        return mInterface->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts);
+            bool enableReadLogs, bool enableReadTimeouts,
+            const std::string& sysfsName) const final {
+        return mInterface->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts,
+                                                sysfsName);
     }
 
 private:
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index c0ef7ba..39e2ee3 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -58,7 +58,7 @@
                                      const std::string& targetDir) const = 0;
     virtual binder::Status setIncFsMountOptions(
             const os::incremental::IncrementalFileSystemControlParcel& control, bool enableReadLogs,
-            bool enableReadTimeouts) const = 0;
+            bool enableReadTimeouts, const std::string& sysfsName) const = 0;
 };
 
 class DataLoaderManagerWrapper {
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 6c9310b..fae654e 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -56,10 +56,10 @@
     MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
     MOCK_CONST_METHOD2(bindMount,
                        binder::Status(const std::string& sourceDir, const std::string& argetDir));
-    MOCK_CONST_METHOD3(
+    MOCK_CONST_METHOD4(
             setIncFsMountOptions,
             binder::Status(const ::android::os::incremental::IncrementalFileSystemControlParcel&,
-                           bool, bool));
+                           bool, bool, const std::string&));
 
     void mountIncFsFails() {
         ON_CALL(*this, mountIncFs(_, _, _, _, _))
@@ -83,12 +83,12 @@
         ON_CALL(*this, bindMount(_, _)).WillByDefault(Return(binder::Status::ok()));
     }
     void setIncFsMountOptionsFails() const {
-        ON_CALL(*this, setIncFsMountOptions(_, _, _))
+        ON_CALL(*this, setIncFsMountOptions(_, _, _, _))
                 .WillByDefault(Return(
                         binder::Status::fromExceptionCode(1, String8("failed to set options"))));
     }
     void setIncFsMountOptionsSuccess() {
-        ON_CALL(*this, setIncFsMountOptions(_, _, _))
+        ON_CALL(*this, setIncFsMountOptions(_, _, _, _))
                 .WillByDefault(Invoke(this, &MockVoldService::setIncFsMountOptionsOk));
     }
     binder::Status getInvalidControlParcel(const std::string& imagePath,
@@ -108,7 +108,7 @@
     }
     binder::Status setIncFsMountOptionsOk(
             const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
-            bool enableReadLogs, bool enableReadTimeouts) {
+            bool enableReadLogs, bool enableReadTimeouts, const std::string& sysfsName) {
         mReadLogsEnabled = enableReadLogs;
         mReadTimeoutsEnabled = enableReadTimeouts;
         return binder::Status::ok();
@@ -1451,9 +1451,9 @@
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // on startLoading
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _, _)).Times(1);
     // We are calling setIncFsMountOptions(true).
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _, _)).Times(1);
     // After setIncFsMountOptions succeeded expecting to start watching.
     EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
     // Not expecting callback removal.
@@ -1475,8 +1475,8 @@
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // Enabling and then disabling readlogs.
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(2);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _, _)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _, _)).Times(2);
     // After setIncFsMountOptions succeeded expecting to start watching.
     EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
     // Not expecting callback removal.
@@ -1503,8 +1503,8 @@
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // Enabling and then disabling readlogs.
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(2);
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(2);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _, _)).Times(2);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _, _)).Times(2);
     // After setIncFsMountOptions succeeded expecting to start watching.
     EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
     // Not expecting callback removal.
@@ -1544,8 +1544,8 @@
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // Enabling and then disabling readlogs.
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(3);
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _, _)).Times(3);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _, _)).Times(1);
     // After setIncFsMountOptions succeeded expecting to start watching.
     EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
     // Not expecting callback removal.
@@ -1585,8 +1585,8 @@
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(2);
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // Enabling and then disabling readlogs.
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(5);
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(3);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _, _)).Times(5);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _, _)).Times(3);
     // After setIncFsMountOptions succeeded expecting to start watching.
     EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
     // Not expecting callback removal.
@@ -1660,9 +1660,9 @@
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // We are calling setIncFsMountOptions(true).
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _, _)).Times(1);
     // setIncFsMountOptions(false) is called on the callback.
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(2);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _, _)).Times(2);
     // After setIncFsMountOptions succeeded expecting to start watching.
     EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
     // After callback is called, disable read logs and remove callback.
@@ -1685,8 +1685,8 @@
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // checkPermission fails, no calls to set opitions,  start or stop WatchingMode.
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(0);
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _, _)).Times(0);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _, _)).Times(1);
     EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
     EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
     TemporaryDir tempDir;
@@ -1705,8 +1705,8 @@
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // checkPermission fails, no calls to set opitions,  start or stop WatchingMode.
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(0);
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _, _)).Times(0);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _, _)).Times(1);
     EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
     EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
     TemporaryDir tempDir;
@@ -1726,8 +1726,8 @@
     EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     // We are calling setIncFsMountOptions.
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _)).Times(1);
-    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true, _, _)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false, _, _)).Times(1);
     // setIncFsMountOptions fails, no calls to start or stop WatchingMode.
     EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
     EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
diff --git a/services/net/TEST_MAPPING b/services/net/TEST_MAPPING
index 7025dd1..7eca1f9 100644
--- a/services/net/TEST_MAPPING
+++ b/services/net/TEST_MAPPING
@@ -2,6 +2,9 @@
   "imports": [
     {
       "path": "frameworks/base/core/java/android/net"
+    },
+    {
+      "path": "packages/modules/Wifi/framework"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 7234281..5222511 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -2403,6 +2403,34 @@
     }
 
     @Test
+    public void opScheduleExactAlarmGranted() throws Exception {
+        final long durationMs = 20000L;
+        when(mActivityManagerInternal.getBootTimeTempAllowListDuration()).thenReturn(durationMs);
+
+        mockExactAlarmPermissionGrant(true, false, MODE_ALLOWED);
+        mIAppOpsCallback.opChanged(OP_SCHEDULE_EXACT_ALARM, TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+
+        verify(mMockContext).sendBroadcastAsUser(intentCaptor.capture(), eq(UserHandle.SYSTEM),
+                isNull(), bundleCaptor.capture());
+
+        // Validate the intent.
+        assertEquals(AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED,
+                intentCaptor.getValue().getAction());
+        assertEquals(TEST_CALLING_PACKAGE, intentCaptor.getValue().getPackage());
+
+        // Validate the options.
+        final BroadcastOptions bOptions = new BroadcastOptions(bundleCaptor.getValue());
+        assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                bOptions.getTemporaryAppAllowlistType());
+        assertEquals(durationMs, bOptions.getTemporaryAppAllowlistDuration());
+        assertEquals(PowerExemptionManager.REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED,
+                bOptions.getTemporaryAppAllowlistReasonCode());
+    }
+
+    @Test
     public void removeExactAlarmsOnPermissionRevoked() {
         doReturn(true).when(
                 () -> CompatChanges.isChangeEnabled(eq(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION),
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
index 8fe1139..d3feb12 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
@@ -75,10 +75,14 @@
                                         .setPropertyName(propertyKeyString)
                                         .addSnippetMatches(
                                                 SnippetMatchProto.newBuilder()
-                                                        .setExactMatchPosition(29)
-                                                        .setExactMatchBytes(3)
-                                                        .setWindowPosition(26)
-                                                        .setWindowBytes(6)))
+                                                        .setExactMatchBytePosition(29)
+                                                        .setExactMatchByteLength(3)
+                                                        .setExactMatchUtf16Position(29)
+                                                        .setExactMatchUtf16Length(3)
+                                                        .setWindowBytePosition(26)
+                                                        .setWindowByteLength(6)
+                                                        .setWindowUtf16Position(26)
+                                                        .setWindowUtf16Length(6)))
                         .build();
         SearchResultProto searchResultProto =
                 SearchResultProto.newBuilder()
@@ -168,19 +172,27 @@
                                         .setPropertyName("senderName")
                                         .addSnippetMatches(
                                                 SnippetMatchProto.newBuilder()
-                                                        .setExactMatchPosition(0)
-                                                        .setExactMatchBytes(4)
-                                                        .setWindowPosition(0)
-                                                        .setWindowBytes(9)))
+                                                        .setExactMatchBytePosition(0)
+                                                        .setExactMatchByteLength(4)
+                                                        .setExactMatchUtf16Position(0)
+                                                        .setExactMatchUtf16Length(4)
+                                                        .setWindowBytePosition(0)
+                                                        .setWindowByteLength(9)
+                                                        .setWindowUtf16Position(0)
+                                                        .setWindowUtf16Length(9)))
                         .addEntries(
                                 SnippetProto.EntryProto.newBuilder()
                                         .setPropertyName("senderEmail")
                                         .addSnippetMatches(
                                                 SnippetMatchProto.newBuilder()
-                                                        .setExactMatchPosition(0)
-                                                        .setExactMatchBytes(20)
-                                                        .setWindowPosition(0)
-                                                        .setWindowBytes(20)))
+                                                        .setExactMatchBytePosition(0)
+                                                        .setExactMatchByteLength(20)
+                                                        .setExactMatchUtf16Position(0)
+                                                        .setExactMatchUtf16Length(20)
+                                                        .setWindowBytePosition(0)
+                                                        .setWindowByteLength(20)
+                                                        .setWindowUtf16Position(0)
+                                                        .setWindowUtf16Length(20)))
                         .build();
         SearchResultProto searchResultProto =
                 SearchResultProto.newBuilder()
@@ -251,19 +263,27 @@
                                         .setPropertyName("sender.name")
                                         .addSnippetMatches(
                                                 SnippetMatchProto.newBuilder()
-                                                        .setExactMatchPosition(0)
-                                                        .setExactMatchBytes(4)
-                                                        .setWindowPosition(0)
-                                                        .setWindowBytes(9)))
+                                                        .setExactMatchBytePosition(0)
+                                                        .setExactMatchByteLength(4)
+                                                        .setExactMatchUtf16Position(0)
+                                                        .setExactMatchUtf16Length(4)
+                                                        .setWindowBytePosition(0)
+                                                        .setWindowByteLength(9)
+                                                        .setWindowUtf16Position(0)
+                                                        .setWindowUtf16Length(9)))
                         .addEntries(
                                 SnippetProto.EntryProto.newBuilder()
                                         .setPropertyName("sender.email[1]")
                                         .addSnippetMatches(
                                                 SnippetMatchProto.newBuilder()
-                                                        .setExactMatchPosition(0)
-                                                        .setExactMatchBytes(21)
-                                                        .setWindowPosition(0)
-                                                        .setWindowBytes(21)))
+                                                        .setExactMatchBytePosition(0)
+                                                        .setExactMatchByteLength(21)
+                                                        .setExactMatchUtf16Position(0)
+                                                        .setExactMatchUtf16Length(21)
+                                                        .setWindowBytePosition(0)
+                                                        .setWindowByteLength(21)
+                                                        .setWindowUtf16Position(0)
+                                                        .setWindowUtf16Length(21)))
                         .build();
         SearchResultProto searchResultProto =
                 SearchResultProto.newBuilder()
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
index 5c7ccfc..2d03981 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
@@ -265,4 +265,36 @@
         assertThat(sStats.getDocumentRetrievingLatencyMillis())
                 .isEqualTo(nativeDocumentRetrievingLatencyMillis);
     }
+
+    @Test
+    public void testAppSearchStats_SetSchemaStats() {
+        int nativeLatencyMillis = 1;
+        int newTypeCount = 2;
+        int compatibleTypeChangeCount = 3;
+        int indexIncompatibleTypeChangeCount = 4;
+        int backwardsIncompatibleTypeChangeCount = 5;
+        final SetSchemaStats sStats =
+                new SetSchemaStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
+                        .setStatusCode(TEST_STATUS_CODE)
+                        .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
+                        .setNativeLatencyMillis(nativeLatencyMillis)
+                        .setNewTypeCount(newTypeCount)
+                        .setCompatibleTypeChangeCount(compatibleTypeChangeCount)
+                        .setIndexIncompatibleTypeChangeCount(indexIncompatibleTypeChangeCount)
+                        .setBackwardsIncompatibleTypeChangeCount(
+                                backwardsIncompatibleTypeChangeCount)
+                        .build();
+
+        assertThat(sStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
+        assertThat(sStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
+        assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+        assertThat(sStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
+        assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
+        assertThat(sStats.getNewTypeCount()).isEqualTo(newTypeCount);
+        assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(compatibleTypeChangeCount);
+        assertThat(sStats.getIndexIncompatibleTypeChangeCount())
+                .isEqualTo(indexIncompatibleTypeChangeCount);
+        assertThat(sStats.getBackwardsIncompatibleTypeChangeCount())
+                .isEqualTo(backwardsIncompatibleTypeChangeCount);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
index 5de8a7a..217430c 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
@@ -89,7 +89,7 @@
                 CallStats.CALL_TYPE_INITIALIZE).mSamplingRatio).isEqualTo(
                 TEST_DEFAULT_SAMPLING_RATIO);
         assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
-                CallStats.CALL_TYPE_QUERY).mSamplingRatio).isEqualTo(
+                CallStats.CALL_TYPE_SEARCH).mSamplingRatio).isEqualTo(
                 TEST_DEFAULT_SAMPLING_RATIO);
         assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
                 CallStats.CALL_TYPE_FLUSH).mSamplingRatio).isEqualTo(
@@ -103,7 +103,7 @@
         int querySamplingRatio = 2;
         final SparseIntArray samplingRatios = new SparseIntArray();
         samplingRatios.put(CallStats.CALL_TYPE_PUT_DOCUMENT, putDocumentSamplingRatio);
-        samplingRatios.put(CallStats.CALL_TYPE_QUERY, querySamplingRatio);
+        samplingRatios.put(CallStats.CALL_TYPE_SEARCH, querySamplingRatio);
         PlatformLogger logger = new PlatformLogger(
                 ApplicationProvider.getApplicationContext(),
                 UserHandle.USER_NULL,
@@ -127,7 +127,7 @@
                 CallStats.CALL_TYPE_PUT_DOCUMENT).mSamplingRatio).isEqualTo(
                 putDocumentSamplingRatio);
         assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
-                CallStats.CALL_TYPE_QUERY).mSamplingRatio).isEqualTo(
+                CallStats.CALL_TYPE_SEARCH).mSamplingRatio).isEqualTo(
                 querySamplingRatio);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
index 0b59be6..39c51d5 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
@@ -18,6 +18,10 @@
 
 import static junit.framework.Assert.assertEquals;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -26,6 +30,7 @@
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.face.FaceSensorProperties;
 import android.hardware.face.FaceSensorPropertiesInternal;
+import android.hardware.face.IFaceServiceReceiver;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.UserManager;
@@ -42,8 +47,12 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.IntStream;
 
 @Presubmit
 @SmallTest
@@ -51,6 +60,7 @@
 
     private static final String TAG = "Face10Test";
     private static final int SENSOR_ID = 1;
+    private static final int USER_ID = 20;
 
     @Mock
     private Context mContext;
@@ -86,10 +96,18 @@
                 FaceSensorProperties.TYPE_UNKNOWN, supportsFaceDetection, supportsSelfIllumination,
                 resetLockoutRequiresChallenge);
 
+        Face10.sSystemClock = Clock.fixed(Instant.ofEpochMilli(100), ZoneId.of("PST"));
         mFace10 = new Face10(mContext, sensorProps, mLockoutResetDispatcher, mScheduler);
         mBinder = new Binder();
     }
 
+    private void tick(long seconds) {
+        waitForIdle();
+        Face10.sSystemClock = Clock.fixed(Instant.ofEpochSecond(
+                Face10.sSystemClock.instant().getEpochSecond() + seconds),
+                ZoneId.of("PST"));
+    }
+
     @Test
     public void getAuthenticatorId_doesNotCrashWhenIdNotFound() {
         assertEquals(0, mFace10.getAuthenticatorId(0 /* sensorId */, 111 /* userId */));
@@ -104,6 +122,59 @@
     }
 
     @Test
+    public void scheduleGenerateChallenge_cachesResult() {
+        final IFaceServiceReceiver[] mocks = IntStream.range(0, 3)
+                .mapToObj(i -> mock(IFaceServiceReceiver.class))
+                .toArray(IFaceServiceReceiver[]::new);
+        for (IFaceServiceReceiver mock : mocks) {
+            mFace10.scheduleGenerateChallenge(SENSOR_ID, USER_ID, mBinder, mock, TAG);
+            tick(10);
+        }
+        tick(120);
+        mFace10.scheduleGenerateChallenge(
+                SENSOR_ID, USER_ID, mBinder, mock(IFaceServiceReceiver.class), TAG);
+        waitForIdle();
+
+        verify(mScheduler, times(2))
+                .scheduleClientMonitor(isA(FaceGenerateChallengeClient.class), any());
+    }
+
+    @Test
+    public void scheduleRevokeChallenge_waitsUntilEmpty() {
+        final long challenge = 22;
+        final IFaceServiceReceiver[] mocks = IntStream.range(0, 3)
+                .mapToObj(i -> mock(IFaceServiceReceiver.class))
+                .toArray(IFaceServiceReceiver[]::new);
+        for (IFaceServiceReceiver mock : mocks) {
+            mFace10.scheduleGenerateChallenge(SENSOR_ID, USER_ID, mBinder, mock, TAG);
+            tick(10);
+        }
+        for (IFaceServiceReceiver mock : mocks) {
+            mFace10.scheduleRevokeChallenge(SENSOR_ID, USER_ID, mBinder, TAG, challenge);
+            tick(10);
+        }
+        waitForIdle();
+
+        verify(mScheduler).scheduleClientMonitor(isA(FaceRevokeChallengeClient.class), any());
+    }
+
+    @Test
+    public void scheduleRevokeChallenge_doesNotWaitForever() {
+        mFace10.scheduleGenerateChallenge(
+                SENSOR_ID, USER_ID, mBinder, mock(IFaceServiceReceiver.class), TAG);
+        mFace10.scheduleGenerateChallenge(
+                SENSOR_ID, USER_ID, mBinder, mock(IFaceServiceReceiver.class), TAG);
+        tick(10000);
+        mFace10.scheduleGenerateChallenge(
+                SENSOR_ID, USER_ID, mBinder, mock(IFaceServiceReceiver.class), TAG);
+        mFace10.scheduleRevokeChallenge(
+                SENSOR_ID, USER_ID, mBinder, TAG, 8 /* challenge */);
+        waitForIdle();
+
+        verify(mScheduler).scheduleClientMonitor(isA(FaceRevokeChallengeClient.class), any());
+    }
+
+    @Test
     public void halServiceDied_resetsScheduler() {
         // It's difficult to test the linkToDeath --> serviceDied path, so let's just invoke
         // serviceDied directly.
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClientTest.java
new file mode 100644
index 0000000..55dc035
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClientTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.face.hidl;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.biometrics.face.V1_0.IBiometricsFace;
+import android.hardware.biometrics.face.V1_0.OptionalUint64;
+import android.hardware.face.IFaceServiceReceiver;
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@SmallTest
+public class FaceGenerateChallengeClientTest {
+
+    private static final String TAG = "FaceGenerateChallengeClientTest";
+    private static final int USER_ID = 2;
+    private static final int SENSOR_ID = 4;
+    private static final long START_TIME = 5000;
+    private static final long CHALLENGE = 200;
+
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+
+    @Mock
+    private IBiometricsFace mIBiometricsFace;
+    @Mock
+    private IFaceServiceReceiver mClientReceiver;
+    @Mock
+    private IFaceServiceReceiver mOtherReceiver;
+    @Mock
+    private BaseClientMonitor.Callback mMonitorCallback;
+
+    private FaceGenerateChallengeClient mClient;
+
+    @Before
+    public void setup() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        final OptionalUint64 challenge = new OptionalUint64();
+        challenge.value = CHALLENGE;
+        when(mIBiometricsFace.generateChallenge(anyInt())).thenReturn(challenge);
+
+        mClient = new FaceGenerateChallengeClient(mContext, () -> mIBiometricsFace, new Binder(),
+                new ClientMonitorCallbackConverter(mClientReceiver), USER_ID,
+                TAG, SENSOR_ID, START_TIME);
+    }
+
+    @Test
+    public void getCreatedAt() {
+        assertEquals(START_TIME, mClient.getCreatedAt());
+    }
+
+    @Test
+    public void reuseResult_whenNotReady() throws Exception {
+        mClient.reuseResult(mOtherReceiver);
+        verify(mOtherReceiver, never()).onChallengeGenerated(anyInt(), anyInt(), anyInt());
+    }
+
+    @Test
+    public void reuseResult_whenReady() throws Exception {
+        mClient.start(mMonitorCallback);
+        mClient.reuseResult(mOtherReceiver);
+        verify(mOtherReceiver).onChallengeGenerated(eq(SENSOR_ID), eq(USER_ID), eq(CHALLENGE));
+    }
+
+    @Test
+    public void reuseResult_whenReallyReady() throws Exception {
+        mClient.reuseResult(mOtherReceiver);
+        mClient.start(mMonitorCallback);
+        verify(mOtherReceiver).onChallengeGenerated(eq(SENSOR_ID), eq(USER_ID), eq(CHALLENGE));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index c54dffc..2270943 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -41,6 +41,7 @@
 import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE;
 import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION;
 import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 import static com.android.server.testutils.TestUtils.assertExpectException;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -82,6 +83,7 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.FactoryResetProtectionPolicy;
 import android.app.admin.PasswordMetrics;
+import android.app.admin.SystemUpdatePolicy;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -3888,37 +3890,28 @@
     public void testForceUpdateUserSetupComplete_permission() {
         // GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted
         assertExpectException(SecurityException.class, /* messageRegex =*/ null,
-                () -> dpm.forceUpdateUserSetupComplete());
-    }
-
-    @Test
-    public void testForceUpdateUserSetupComplete_systemUser() {
-        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
-        // GIVEN calling from user 20
-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
-        assertExpectException(SecurityException.class, /* messageRegex =*/ null,
-                () -> dpm.forceUpdateUserSetupComplete());
+                () -> dpm.forceUpdateUserSetupComplete(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void testForceUpdateUserSetupComplete_forcesUpdate() {
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+        final int userId = UserHandle.getUserId(mContext.binder.callingUid);
 
-        final int userId = UserHandle.USER_SYSTEM;
         // GIVEN userComplete is false in SettingsProvider
         setUserSetupCompleteForUser(false, userId);
 
         // GIVEN userComplete is true in DPM
         DevicePolicyData userData = new DevicePolicyData(userId);
         userData.mUserSetupComplete = true;
-        dpms.mUserData.put(UserHandle.USER_SYSTEM, userData);
+        dpms.mUserData.put(userId, userData);
 
         assertThat(dpms.hasUserSetupCompleted()).isTrue();
 
-        dpm.forceUpdateUserSetupComplete();
+        dpm.forceUpdateUserSetupComplete(userId);
 
-        // THEN the state in dpms is not changed
+        // THEN the state in dpms is changed
         assertThat(dpms.hasUserSetupCompleted()).isFalse();
     }
 
@@ -3948,10 +3941,9 @@
 
         // Enabling logging should not change the timestamp.
         dpm.setSecurityLoggingEnabled(admin1, true);
-        verify(getServices().settings)
-                .securityLogSetLoggingEnabledProperty(true);
-        when(getServices().settings.securityLogGetLoggingEnabledProperty())
-                .thenReturn(true);
+        verify(getServices().settings).securityLogSetLoggingEnabledProperty(true);
+
+        when(getServices().settings.securityLogGetLoggingEnabledProperty()).thenReturn(true);
         assertThat(dpm.getLastSecurityLogRetrievalTime()).isEqualTo(-1);
 
         // Retrieving the logs should update the timestamp.
@@ -4776,8 +4768,8 @@
         when(getServices().iactivityManager.getCurrentUser())
                 .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
         // Get mock reason string since we throw an IAE with empty string input.
-        when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe)).
-                thenReturn("Just a test string.");
+        when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe))
+                .thenReturn("Just a test string.");
 
         dpm.wipeData(0);
         verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed(
@@ -4785,6 +4777,68 @@
     }
 
     @Test
+    public void testWipeDataManagedProfileOnOrganizationOwnedDevice() throws Exception {
+        setupProfileOwner();
+        configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
+
+        // Even if the caller is the managed profile, the current user is the user 0
+        when(getServices().iactivityManager.getCurrentUser())
+                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+        // Get mock reason string since we throw an IAE with empty string input.
+        when(mContext.getResources().getString(R.string.work_profile_deleted_description_dpm_wipe))
+                .thenReturn("Just a test string.");
+        when(getServices().userManager.getProfileParent(CALLER_USER_HANDLE))
+                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+        when(getServices().userManager.getPrimaryUser())
+                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
+
+        // Set some device-wide policies:
+        // Security logging
+        when(getServices().settings.securityLogGetLoggingEnabledProperty()).thenReturn(true);
+        // System update policy
+        dpms.mOwners.setSystemUpdatePolicy(SystemUpdatePolicy.createAutomaticInstallPolicy());
+        // Make it look as if FRP agent is present.
+        when(dpms.mMockInjector.getPersistentDataBlockManagerInternal().getAllowedUid())
+                .thenReturn(12345 /* some UID in user 0 */);
+        // Make personal apps look suspended
+        dpms.getUserData(UserHandle.USER_SYSTEM).mAppsSuspended = true;
+
+        clearInvocations(getServices().iwindowManager);
+
+        dpm.wipeData(0);
+        verify(getServices().userManagerInternal).removeUserEvenWhenDisallowed(CALLER_USER_HANDLE);
+
+        // Make sure COPE restrictions are lifted:
+        verify(getServices().userManager).setUserRestriction(
+                UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false, UserHandle.SYSTEM);
+        verify(getServices().userManager).setUserRestriction(
+                UserManager.DISALLOW_ADD_USER, false, UserHandle.SYSTEM);
+
+        // Some device-wide policies are getting cleaned-up after the user is removed.
+        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+        sendBroadcastWithUser(dpms, Intent.ACTION_USER_REMOVED, CALLER_USER_HANDLE);
+
+        // Screenlock info should be removed
+        verify(getServices().lockPatternUtils).setDeviceOwnerInfo(null);
+        // Wifi config lockdown should be lifted
+        verify(getServices().settings).settingsGlobalPutInt(
+                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0);
+        // System update policy should be removed
+        assertThat(dpms.mOwners.getSystemUpdatePolicy()).isNull();
+        // FRP agent should be notified
+        verify(mContext.spiedContext, times(0)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_RESET_PROTECTION_POLICY_CHANGED),
+                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
+        // Refresh strong auth timeout and screen capture
+        verify(getServices().lockSettingsInternal).refreshStrongAuthTimeout(UserHandle.USER_SYSTEM);
+        verify(getServices().iwindowManager).refreshScreenCaptureDisabled(UserHandle.USER_SYSTEM);
+        // Unsuspend personal apps
+        verify(getServices().packageManagerInternal)
+                .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, UserHandle.USER_SYSTEM);
+    }
+
+    @Test
     public void testWipeDataManagedProfileDisallowed() throws Exception {
         final int MANAGED_PROFILE_USER_ID = 15;
         final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
index 7b48037..5caff3d 100644
--- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
+++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java
@@ -90,6 +90,10 @@
             String content = FileUtils.readTextFile(file, 100, "");
             return Long.parseLong(content.split(",")[1]);
         }
+
+        @Override
+        public void tryToCreateTypeface(File file) throws IOException {
+        }
     }
 
     // FakeFsverityUtil will successfully set up fake fs-verity if the signature is GOOD_SIGNATURE.
@@ -717,6 +721,10 @@
                     public long getRevision(File file) throws IOException {
                         return 0;
                     }
+
+                    @Override
+                    public void tryToCreateTypeface(File file) throws IOException {
+                    }
                 }, fakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
         dir.loadFontFileMap();
 
@@ -751,6 +759,50 @@
                     public long getRevision(File file) throws IOException {
                         return 0;
                     }
+
+                    @Override
+                    public void tryToCreateTypeface(File file) throws IOException {
+                    }
+                }, fakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
+        dir.loadFontFileMap();
+
+        try {
+            dir.update(Collections.singletonList(newFontUpdateRequest("foo.ttf,1,foo",
+                    GOOD_SIGNATURE)));
+            fail("Expect SystemFontException");
+        } catch (FontManagerService.SystemFontException e) {
+            assertThat(e.getErrorCode())
+                    .isEqualTo(FontManager.RESULT_ERROR_INVALID_FONT_FILE);
+        }
+        assertThat(dir.getPostScriptMap()).isEmpty();
+    }
+
+    @Test
+    public void installFontFile_failedToCreateTypeface() throws Exception {
+        FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+        FakeFontFileParser parser = new FakeFontFileParser();
+        UpdatableFontDir dir = new UpdatableFontDir(
+                mUpdatableFontFilesDir,
+                new UpdatableFontDir.FontFileParser() {
+                    @Override
+                    public String getPostScriptName(File file) throws IOException {
+                        return parser.getPostScriptName(file);
+                    }
+
+                    @Override
+                    public String buildFontFileName(File file) throws IOException {
+                        return parser.buildFontFileName(file);
+                    }
+
+                    @Override
+                    public long getRevision(File file) throws IOException {
+                        return parser.getRevision(file);
+                    }
+
+                    @Override
+                    public void tryToCreateTypeface(File file) throws IOException {
+                        throw new IOException();
+                    }
                 }, fakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
         dir.loadFontFileMap();
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index c08857c..6cc8d471 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -68,10 +68,12 @@
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
-        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
+        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         mHdmiControlService = new HdmiControlService(mContextSpy) {
@@ -97,7 +99,8 @@
 
             @Override
             protected PowerManager getPowerManager() {
-                return powerManager;
+                return new PowerManager(mContextSpy, mIPowerManagerMock,
+                        mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
             }
 
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index ee9de07..97bd066 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -70,10 +70,12 @@
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
-        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
+        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         HdmiControlService hdmiControlService =
@@ -89,7 +91,8 @@
 
                     @Override
                     protected PowerManager getPowerManager() {
-                        return powerManager;
+                        return new PowerManager(mContextSpy, mIPowerManagerMock,
+                                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
                     }
 
                     @Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index d5df071..29c9b40 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -71,10 +71,12 @@
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
-        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
+        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         HdmiControlService hdmiControlService =
@@ -85,7 +87,8 @@
 
                     @Override
                     protected PowerManager getPowerManager() {
-                        return powerManager;
+                        return new PowerManager(mContextSpy, mIPowerManagerMock,
+                                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
                     }
 
                     @Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
index 4f97c26..650ffe9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DevicePowerStatusActionTest.java
@@ -80,10 +80,12 @@
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
-        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
+        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         mHdmiControlService = new HdmiControlService(mContextSpy) {
@@ -109,7 +111,8 @@
 
             @Override
             protected PowerManager getPowerManager() {
-                return powerManager;
+                return new PowerManager(mContextSpy, mIPowerManagerMock,
+                        mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
             }
 
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
index 678f8b2..fa5cb67 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionTest.java
@@ -103,8 +103,6 @@
 
         Context context = InstrumentationRegistry.getTargetContext();
         mMyLooper = mTestLooper.getLooper();
-        PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mMyLooper));
 
         mHdmiControlService =
                 new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@@ -129,7 +127,8 @@
 
                     @Override
                     protected PowerManager getPowerManager() {
-                        return powerManager;
+                        return new PowerManager(context, mIPowerManagerMock,
+                                mIThermalServiceMock, new Handler(mMyLooper));
                     }
                 };
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index e2b6a99..41946fb 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -26,6 +26,8 @@
 
 import com.android.internal.R;
 
+import java.util.HashMap;
+
 /**
  * Fake class which stubs default system configuration with user-configurable
  * settings (useful for testing).
@@ -33,6 +35,8 @@
 final class FakeHdmiCecConfig extends HdmiCecConfig {
     private static final String TAG = "FakeHdmiCecConfig";
 
+    private final HashMap<String, String> mSettings = new HashMap<>();
+
     public static Context buildContext(Context context) {
         Context contextSpy = spy(new ContextWrapper(context));
         doReturn(buildResources(context)).when(contextSpy).getResources();
@@ -218,4 +222,15 @@
     FakeHdmiCecConfig(@NonNull Context context) {
         super(buildContext(context), new StorageAdapter(context));
     }
+
+    @Override
+    protected String retrieveValue(@NonNull Setting setting, @NonNull String defaultValue) {
+        return mSettings.getOrDefault(setting.getName(), defaultValue);
+    }
+
+    @Override
+    protected void storeValue(@NonNull Setting setting, @NonNull String value) {
+        mSettings.put(setting.getName(), value);
+        notifySettingChanged(setting);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
index 45409c8..29f62b5 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -96,9 +97,10 @@
         mContextSpy = spy(new ContextWrapper(
                 InstrumentationRegistry.getInstrumentation().getTargetContext()));
 
-        PowerManager powerManager = new PowerManager(
-                mContextSpy, mIPowerManagerMock, mIThermalServiceMock, new Handler(mLooper));
-        doReturn(powerManager).when(mContextSpy).getSystemService(Context.POWER_SERVICE);
+
+        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                        mIThermalServiceMock, new Handler(mLooper)));
         doReturn(true).when(mIPowerManagerMock).isInteractive();
 
         mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy));
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 38a44c6..7911c40 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -94,8 +94,6 @@
 
         Context context = InstrumentationRegistry.getTargetContext();
         mMyLooper = mTestLooper.getLooper();
-        PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mMyLooper));
 
         mHdmiControlService =
             new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@@ -183,7 +181,8 @@
 
                 @Override
                 protected PowerManager getPowerManager() {
-                    return powerManager;
+                    return new PowerManager(context, mIPowerManagerMock,
+                            mIThermalServiceMock, new Handler(mMyLooper));
                 }
             };
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 1ac0150..5fbf8de 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -92,8 +92,6 @@
 
         Context context = InstrumentationRegistry.getTargetContext();
         mMyLooper = mTestLooper.getLooper();
-        PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mMyLooper));
 
         mHdmiControlService =
                 new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@@ -140,7 +138,8 @@
 
                     @Override
                     protected PowerManager getPowerManager() {
-                        return powerManager;
+                        return new PowerManager(context, mIPowerManagerMock,
+                                mIThermalServiceMock, new Handler(mMyLooper));
                     }
                 };
 
@@ -168,6 +167,8 @@
         mPlaybackLogicalAddress = mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress();
         mHdmiControlService.getHdmiCecNetwork().addCecDevice(INFO_TV);
         mNativeWrapper.clearResultMessages();
+        mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
+                HdmiProperties.playback_device_action_on_routing_control_values.NONE;
     }
 
     @Test
@@ -698,9 +699,12 @@
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+        HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
 
     @Test
@@ -720,9 +724,12 @@
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+        HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
 
     @Test
@@ -742,9 +749,12 @@
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+        HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
 
     @Test
@@ -764,9 +774,12 @@
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+        HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageToTv);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
 
     @Test
@@ -786,9 +799,12 @@
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+        HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
         assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageBroadcast);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(inactiveSource);
     }
 
     @Test
@@ -808,9 +824,37 @@
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
         HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
                 mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+        HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+        assertThat(mNativeWrapper.getResultMessages()).contains(inactiveSource);
+    }
+
+    @Test
+    public void handleOnStandby_CecMessageReceived() {
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV);
+        mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+                mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP,
+                HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
+        mHdmiCecLocalDevicePlayback.onStandby(true, HdmiControlService.STANDBY_SCREEN_OFF);
+        mTestLooper.dispatchAll();
+
+        HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+        HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+                mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+        HdmiCecMessage inactiveSource = HdmiCecMessageBuilder.buildInactiveSource(
+                mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
+
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+        assertThat(mNativeWrapper.getResultMessages()).contains(inactiveSource);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 8ee983f..59711a6 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -86,8 +86,6 @@
 
         Context context = InstrumentationRegistry.getTargetContext();
         mMyLooper = mTestLooper.getLooper();
-        PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mMyLooper));
 
         mHdmiControlService =
                 new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@@ -118,7 +116,8 @@
 
                     @Override
                     protected PowerManager getPowerManager() {
-                        return powerManager;
+                        return new PowerManager(context, mIPowerManagerMock,
+                                mIThermalServiceMock, new Handler(mMyLooper));
                     }
 
                     @Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index 1c7ff42..572ffd9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -75,10 +75,12 @@
 
         Context contextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
         Looper myLooper = mTestLooper.getLooper();
-        PowerManager powerManager = new PowerManager(contextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(myLooper));
-        when(contextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
-        when(contextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+        when(contextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(contextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(myLooper)));
+        when(contextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
+                new PowerManager(contextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(myLooper)));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         mHdmiControlService = new HdmiControlService(contextSpy) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 68aa96a..bcf30a2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -47,7 +47,6 @@
 import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.platform.test.annotations.Presubmit;
-import android.provider.Settings;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -193,10 +192,12 @@
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, null);
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
-        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, null));
+        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, null));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
@@ -237,9 +238,6 @@
         mHdmiPortInfo[3] =
             new HdmiPortInfo(4, HdmiPortInfo.PORT_INPUT, 0x3000, true, false, false);
         mNativeWrapper.setPortInfo(mHdmiPortInfo);
-        mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
-                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlServiceSpy.initService();
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
 
@@ -362,23 +360,6 @@
     }
 
     @Test
-    public void setAndGetCecVolumeControlEnabled_changesSetting() {
-        mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
-                HdmiControlManager.VOLUME_CONTROL_DISABLED);
-        assertThat(mHdmiControlServiceSpy.readIntSetting(
-                Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, -1)).isEqualTo(
-                HdmiControlManager.VOLUME_CONTROL_DISABLED);
-
-        mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
-                HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
-                HdmiControlManager.VOLUME_CONTROL_ENABLED);
-        assertThat(mHdmiControlServiceSpy.readIntSetting(
-                Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, -1)).isEqualTo(
-                HdmiControlManager.VOLUME_CONTROL_ENABLED);
-    }
-
-    @Test
     public void setAndGetCecVolumeControlEnabledInternal_doesNotChangeSetting() {
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index 826438f..4cd17e8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -91,10 +91,12 @@
 
         setHdmiControlEnabled(hdmiControlEnabled);
 
-        PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
-        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
+        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         mHdmiControlService = new HdmiControlService(mContextSpy) {
@@ -120,7 +122,8 @@
 
             @Override
             protected PowerManager getPowerManager() {
-                return powerManager;
+                return new PowerManager(mContextSpy, mIPowerManagerMock,
+                        mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
             }
 
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
index 53b4b49..a9880c0 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
@@ -78,10 +78,12 @@
 
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
-        PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
-        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
+        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         mHdmiControlService = new HdmiControlService(mContextSpy,
@@ -108,7 +110,8 @@
 
             @Override
             protected PowerManager getPowerManager() {
-                return powerManager;
+                return new PowerManager(mContextSpy, mIPowerManagerMock,
+                        mIThermalServiceMock, new Handler(mTestLooper.getLooper()));
             }
 
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
index 865eb7a..2cf4ef1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioAutoInitiationActionTest.java
@@ -78,10 +78,12 @@
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
         Looper myLooper = mTestLooper.getLooper();
-        PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
-                mIThermalServiceMock, new Handler(myLooper));
-        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
-        when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
+        when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(myLooper)));
+        when(mContextSpy.getSystemService(PowerManager.class)).thenAnswer(i ->
+                new PowerManager(mContextSpy, mIPowerManagerMock,
+                mIThermalServiceMock, new Handler(myLooper)));
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
         mHdmiControlService = new HdmiControlService(mContextSpy) {
@@ -107,7 +109,8 @@
 
             @Override
             protected PowerManager getPowerManager() {
-                return powerManager;
+                return new PowerManager(mContextSpy, mIPowerManagerMock,
+                        mIThermalServiceMock, new Handler(myLooper));
             }
 
             @Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 3581206..4a09cf8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -50,12 +50,14 @@
 import android.app.appsearch.AppSearchManager;
 import android.app.appsearch.AppSearchResult;
 import android.app.appsearch.GenericDocument;
-import android.app.appsearch.IAppSearchBatchResultCallback;
-import android.app.appsearch.IAppSearchManager;
-import android.app.appsearch.IAppSearchResultCallback;
 import android.app.appsearch.PackageIdentifier;
 import android.app.appsearch.SearchResultPage;
 import android.app.appsearch.SetSchemaResponse;
+import android.app.appsearch.aidl.AppSearchBatchResultParcel;
+import android.app.appsearch.aidl.AppSearchResultParcel;
+import android.app.appsearch.aidl.IAppSearchBatchResultCallback;
+import android.app.appsearch.aidl.IAppSearchManager;
+import android.app.appsearch.aidl.IAppSearchResultCallback;
 import android.app.role.OnRoleHoldersChangedListener;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ActivityNotFoundException;
@@ -675,7 +677,9 @@
                 }
             }
             final SetSchemaResponse response = new SetSchemaResponse.Builder().build();
-            callback.onResult(AppSearchResult.newSuccessfulResult(response.getBundle()));
+            callback.onResult(
+                    new AppSearchResultParcel(
+                            AppSearchResult.newSuccessfulResult(response.getBundle())));
         }
 
         @Override
@@ -711,7 +715,7 @@
                 }
                 docMap.put(doc.getId(), doc);
             }
-            callback.onResult(builder.build());
+            callback.onResult(new AppSearchBatchResultParcel<>(builder.build()));
         }
 
         @Override
@@ -737,7 +741,7 @@
                     }
                 }
             }
-            callback.onResult(builder.build());
+            callback.onResult(new AppSearchBatchResultParcel<>(builder.build()));
         }
 
         @Override
@@ -749,7 +753,8 @@
                 final Bundle page = new Bundle();
                 page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1);
                 page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, new ArrayList<>());
-                callback.onResult(AppSearchResult.newSuccessfulResult(page));
+                callback.onResult(
+                        new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(page)));
                 return;
             }
             final List<GenericDocument> documents = new ArrayList<>(mDocumentMap.get(key).values());
@@ -765,7 +770,8 @@
                 resultBundles.add(resultBundle);
             }
             page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
-            callback.onResult(AppSearchResult.newSuccessfulResult(page));
+            callback.onResult(
+                    new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(page)));
         }
 
         @Override
@@ -780,7 +786,8 @@
             final Bundle page = new Bundle();
             page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1);
             page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, new ArrayList<>());
-            callback.onResult(AppSearchResult.newSuccessfulResult(page));
+            callback.onResult(
+                    new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(page)));
         }
 
         @Override
@@ -835,7 +842,7 @@
                     }
                 }
             }
-            callback.onResult(builder.build());
+            callback.onResult(new AppSearchBatchResultParcel<>(builder.build()));
         }
 
         @Override
@@ -844,11 +851,13 @@
                 throws RemoteException {
             final String key = getKey(userId, databaseName);
             if (!mDocumentMap.containsKey(key)) {
-                callback.onResult(AppSearchResult.newSuccessfulResult(null));
+                callback.onResult(
+                        new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(null)));
                 return;
             }
             mDocumentMap.get(key).clear();
-            callback.onResult(AppSearchResult.newSuccessfulResult(null));
+            callback.onResult(
+                    new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(null)));
         }
 
         @Override
@@ -878,7 +887,8 @@
         }
 
         private void ignore(IAppSearchResultCallback callback) throws RemoteException {
-            callback.onResult(AppSearchResult.newSuccessfulResult(null));
+            callback.onResult(
+                    new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(null)));
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
index 478aa41..9598a00 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
@@ -15,20 +15,11 @@
  */
 package com.android.server.pm;
 
-import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
-
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
 
 import android.app.PendingIntent;
-import android.app.appsearch.PackageIdentifier;
-import android.content.pm.AppSearchShortcutInfo;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.DeviceConfig;
-
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-
-import java.util.Random;
 
 /**
  * Tests for {@link android.app.appsearch.AppSearchManager} and relevant APIs in ShortcutManager.
@@ -37,26 +28,6 @@
  */
 public class ShortcutManagerTest12 extends BaseShortcutManagerTest {
 
-    public void testUpdateShortcutVisibility_updatesShortcutSchema() {
-        if (!DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED,
-                false)) {
-            // no-op if app-search integration is disabled.
-            return;
-        }
-        final byte[] cert = new byte[20];
-        new Random().nextBytes(cert);
-
-        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
-            mManager.updateShortcutVisibility(CALLING_PACKAGE_2, cert, true);
-            assertTrue(mMockAppSearchManager.mSchemasPackageAccessible.containsKey(
-                    AppSearchShortcutInfo.SCHEMA_TYPE));
-            assertTrue(mMockAppSearchManager.mSchemasPackageAccessible.get(
-                    AppSearchShortcutInfo.SCHEMA_TYPE).get(0).equals(
-                            new PackageIdentifier(CALLING_PACKAGE_2, cert)));
-        });
-    }
-
     public void testGetShortcutIntents_ReturnsMutablePendingIntents() throws RemoteException {
         setDefaultLauncher(USER_0, LAUNCHER_1);
 
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/OWNERS b/services/tests/servicestests/src/com/android/server/power/batterysaver/OWNERS
new file mode 100644
index 0000000..08276f5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/power/batterysaver/OWNERS
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index c502ed5..825e53e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -100,6 +100,7 @@
     private String mVersionString;
     private final Set<ComponentName> mDefaults = new ArraySet();
     private ManagedServices mService;
+    private String mUserSetString;
 
     private static final String SETTING = "setting";
     private static final String SECONDARY_SETTING = "secondary_setting";
@@ -138,7 +139,7 @@
         profileIds.add(13);
         when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
 
-        mVersionString = "2";
+        mVersionString = "4";
         mExpectedPrimary = new ArrayMap<>();
         mExpectedSecondary = new ArrayMap<>();
         mExpectedPrimaryPackages = new ArrayMap<>();
@@ -1363,6 +1364,7 @@
     public void loadDefaults_noVersionWithDefaults() throws Exception {
         resetComponentsAndPackages();
         mDefaults.add(new ComponentName("default", "class"));
+        mVersionString = null;
         loadXml(mService);
         assertEquals(mService.getDefaultComponents(), mDefaults);
     }
@@ -1421,12 +1423,34 @@
         resetComponentsAndPackages();
         mDefaults.add(new ComponentName("default", "class"));
         mDefaultsString = "xml/class";
-        mVersionString = String.valueOf(mService.DB_VERSION);
         loadXml(mService);
         assertEquals(mService.getDefaultComponents(),
                 new ArraySet(Arrays.asList(new ComponentName("xml", "class"))));
     }
 
+    @Test
+    public void upgradeUserSet_versionThree() throws Exception {
+        resetComponentsAndPackages();
+
+        List<UserInfo> users = new ArrayList<>();
+        users.add(new UserInfo(98, "98", 0));
+        users.add(new UserInfo(99, "99", 0));
+        for (UserInfo user : users) {
+            when(mUm.getUserInfo(eq(user.id))).thenReturn(user);
+        }
+
+        mDefaultsString = "xml/class";
+        mVersionString = "3";
+        mUserSetString = "xml/class";
+        loadXml(mService);
+
+        //Test services without overriding upgradeUserSet() remain unchanged
+        assertEquals(new ArraySet(Arrays.asList(mUserSetString)),
+                mService.mUserSetServices.get(98));
+        assertEquals(new ArraySet(Arrays.asList(mUserSetString)),
+                mService.mUserSetServices.get(99));
+        assertEquals(new ArrayMap(), mService.mIsUserChanged);
+    }
 
     private void resetComponentsAndPackages() {
         ArrayMap<Integer, ArrayMap<Integer, String>> empty = new ArrayMap(1);
@@ -1468,11 +1492,17 @@
         xml.append("<" + ManagedServices.TAG_MANAGED_SERVICES + " "
                         + ManagedServices.ATT_USER_ID + "=\"99\" "
                         + ManagedServices.ATT_IS_PRIMARY + "=\"true\" "
-                        + ManagedServices.ATT_APPROVED_LIST + "=\"990\" />\n");
+                        + ManagedServices.ATT_APPROVED_LIST + "=\"990\" "
+                        + (mUserSetString != null ? ManagedServices.ATT_USER_SET + "=\""
+                        + mUserSetString + "\" " : "")
+                        + "/>\n");
         xml.append("<" + ManagedServices.TAG_MANAGED_SERVICES + " "
                 + ManagedServices.ATT_USER_ID + "=\"98\" "
                 + ManagedServices.ATT_IS_PRIMARY + "=\"false\" "
-                + ManagedServices.ATT_APPROVED_LIST + "=\"981\" />\n");
+                + ManagedServices.ATT_APPROVED_LIST + "=\"981\" "
+                + (mUserSetString != null ? ManagedServices.ATT_USER_SET + "=\""
+                + mUserSetString + "\" " : "")
+                + " />\n");
         xml.append("</" + xmlTag + ">");
 
         return xml.toString();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 6722fff..054a401 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -16,6 +16,7 @@
 package com.android.server.notification;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
 
 import static org.junit.Assert.assertNull;
@@ -41,11 +42,13 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.testing.TestableContext;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IntArray;
 import android.util.TypedXmlPullParser;
 import android.util.Xml;
 
+import com.android.internal.util.function.TriPredicate;
 import com.android.server.UiServiceTestCase;
 import com.android.server.notification.NotificationManagerService.NotificationAssistants;
 
@@ -132,6 +135,68 @@
     }
 
     @Test
+    public void testReadXml_userDisabled() throws Exception {
+        String xml = "<enabled_assistants version=\"4\" defaults=\"b/b\">"
+                + "<service_listing approved=\"\" user=\"0\" primary=\"true\""
+                + "user_changed=\"true\"/>"
+                + "</enabled_assistants>";
+
+        final TypedXmlPullParser parser = Xml.newFastPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.toString().getBytes())), null);
+        TriPredicate<String, Integer, String> allowedManagedServicePackages =
+                mNm::canUseManagedServices;
+
+        parser.nextTag();
+        mAssistants.readXml(parser, allowedManagedServicePackages, false, UserHandle.USER_ALL);
+
+        ArrayMap<Boolean, ArraySet<String>> approved = mAssistants.mApproved.get(0);
+
+        // approved should not be null
+        assertNotNull(approved);
+        assertEquals(new ArraySet<>(), approved.get(true));
+    }
+
+    @Test
+    public void testReadXml_upgradeUserSet() throws Exception {
+        String xml = "<enabled_assistants version=\"3\" defaults=\"b/b\">"
+                + "<service_listing approved=\"\" user=\"0\" primary=\"true\""
+                + "user_set_services=\"b/b\"/>"
+                + "</enabled_assistants>";
+
+        final TypedXmlPullParser parser = Xml.newFastPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.toString().getBytes())), null);
+        TriPredicate<String, Integer, String> allowedManagedServicePackages =
+                mNm::canUseManagedServices;
+
+        parser.nextTag();
+        mAssistants.readXml(parser, allowedManagedServicePackages, false, UserHandle.USER_ALL);
+
+        verify(mAssistants, times(1)).upgradeUserSet();
+        assertTrue(mAssistants.mIsUserChanged.get(0));
+    }
+
+    @Test
+    public void testReadXml_multiApproved() throws Exception {
+        String xml = "<enabled_assistants version=\"4\" defaults=\"b/b\">"
+                + "<service_listing approved=\"a/a:b/b\" user=\"0\" primary=\"true\""
+                + "user_changed=\"true\"/>"
+                + "</enabled_assistants>";
+
+        final TypedXmlPullParser parser = Xml.newFastPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.toString().getBytes())), null);
+
+        parser.nextTag();
+        mAssistants.readXml(parser, null, false, UserHandle.USER_ALL);
+
+        assertEquals(1, mAssistants.getAllowedComponents(0).size());
+        assertEquals(new ArrayList(Arrays.asList(new ComponentName("a", "a"))),
+                mAssistants.getAllowedComponents(0));
+    }
+
+    @Test
     public void testXmlUpgradeExistingApprovedComponents() throws Exception {
         String xml = "<enabled_assistants version=\"2\" defaults=\"b\\b\">"
                 + "<service_listing approved=\"b/b\" user=\"10\" primary=\"true\" />"
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 4bbea94..ddaf3ab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1351,25 +1351,39 @@
      * must ensure the visibilities of activities being updated.
      */
     @Test
-    public void testCompleteFinishing_ensureActivitiesVisible() {
+    public void testCompleteFinishing_ensureActivitiesVisible_withConditions() {
+        testCompleteFinishing_ensureActivitiesVisible(false, PAUSED);
+        testCompleteFinishing_ensureActivitiesVisible(false, STARTED);
+        testCompleteFinishing_ensureActivitiesVisible(true, PAUSED);
+        testCompleteFinishing_ensureActivitiesVisible(true, STARTED);
+    }
+
+    private void testCompleteFinishing_ensureActivitiesVisible(boolean diffTask,
+            ActivityState secondActivityState) {
         final ActivityRecord activity = createActivityWithTask();
         final Task task = activity.getTask();
         final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(task).build();
         firstActivity.mVisibleRequested = false;
         firstActivity.nowVisible = false;
-        firstActivity.setState(STOPPED, "true");
+        firstActivity.setState(STOPPED, "test");
 
         final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task).build();
         secondActivity.mVisibleRequested = true;
         secondActivity.nowVisible = true;
-        secondActivity.setState(PAUSED, "true");
+        secondActivity.setState(secondActivityState, "test");
 
-        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm).setTask(task).build();
+        ActivityRecord translucentActivity;
+        if (diffTask) {
+            translucentActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        } else {
+            translucentActivity = new ActivityBuilder(mAtm).setTask(task).build();
+        }
         translucentActivity.mVisibleRequested = true;
         translucentActivity.nowVisible = true;
-        translucentActivity.setState(RESUMED, "true");
+        translucentActivity.setState(RESUMED, "test");
 
-        doReturn(false).when(translucentActivity).occludesParent();
+        doReturn(true).when(firstActivity).occludesParent(true);
+        doReturn(true).when(secondActivity).occludesParent(true);
 
         // Finish the second activity
         secondActivity.finishing = true;
@@ -1385,6 +1399,10 @@
         verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
                 0 /* configChanges */ , false /* preserveWindows */,
                 true /* notifyClients */);
+
+        // Remove the translucent activity and clear invocations for next test
+        translucentActivity.getTask().removeImmediately("test");
+        clearInvocations(mDefaultDisplay);
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
index 2c3f52e..4509ff4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -268,7 +268,7 @@
 
         // By default, the ime container is attached to DC as defined in DAPolicy.
         assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mDisplay);
-        assertThat(mDisplay.findAreaForToken(imeToken)).isEqualTo(imeContainer);
+        assertThat(mDisplay.findAreaForTokenInLayer(imeToken)).isEqualTo(imeContainer);
 
         final WindowState firstActivityWin =
                 createWindow(null /* parent */, TYPE_APPLICATION_STARTING, mFirstActivity,
@@ -290,9 +290,9 @@
         assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mFirstRoot);
         assertThat(imeContainer.getParent().asDisplayArea().mFeatureId)
                 .isEqualTo(FEATURE_IME_PLACEHOLDER);
-        assertThat(mDisplay.findAreaForToken(imeToken)).isNull();
-        assertThat(mFirstRoot.findAreaForToken(imeToken)).isEqualTo(imeContainer);
-        assertThat(mSecondRoot.findAreaForToken(imeToken)).isNull();
+        assertThat(mDisplay.findAreaForTokenInLayer(imeToken)).isNull();
+        assertThat(mFirstRoot.findAreaForTokenInLayer(imeToken)).isEqualTo(imeContainer);
+        assertThat(mSecondRoot.findAreaForTokenInLayer(imeToken)).isNull();
 
         // secondActivityWin should be the target
         doReturn(false).when(firstActivityWin).canBeImeTarget();
@@ -305,9 +305,9 @@
         assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondRoot);
         assertThat(imeContainer.getParent().asDisplayArea().mFeatureId)
                 .isEqualTo(FEATURE_IME_PLACEHOLDER);
-        assertThat(mDisplay.findAreaForToken(imeToken)).isNull();
-        assertThat(mFirstRoot.findAreaForToken(imeToken)).isNull();
-        assertThat(mSecondRoot.findAreaForToken(imeToken)).isEqualTo(imeContainer);
+        assertThat(mDisplay.findAreaForTokenInLayer(imeToken)).isNull();
+        assertThat(mFirstRoot.findAreaForTokenInLayer(imeToken)).isNull();
+        assertThat(mSecondRoot.findAreaForTokenInLayer(imeToken)).isEqualTo(imeContainer);
     }
 
     @Test
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 748622b..e280a36 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -38,6 +38,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+import static com.android.server.wm.Task.ActivityState.DESTROYED;
 import static com.android.server.wm.Task.ActivityState.DESTROYING;
 import static com.android.server.wm.Task.ActivityState.FINISHING;
 import static com.android.server.wm.Task.ActivityState.PAUSING;
@@ -1204,6 +1205,9 @@
         // See {@link ActivityStack#destroyActivityLocked}.
         activity.app = null;
         overlayActivity.app = null;
+        // Simulate the process is dead
+        activity.mVisibleRequested = false;
+        activity.setState(DESTROYED, "Test");
 
         assertEquals(2, task.getChildCount());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
index 5d0fe17..e5eba57 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
@@ -19,6 +19,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -38,6 +39,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 /**
  * Build/Install/Run:
@@ -185,6 +187,41 @@
         assertThat(mController.getContainer(mClientToken)).isEqualTo(da);
     }
 
+    @Test
+    public void testImeSwitchDialogWindowTokenRemovedOnDualDisplayContent_ListenToImeContainer() {
+        // Let the Display to be created with the DualDisplay policy.
+        final DisplayAreaPolicy.Provider policyProvider =
+                new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider();
+        Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
+        // Create a DisplayContent with dual RootDisplayArea
+        DualDisplayAreaGroupPolicyTest.DualDisplayContent dualDisplayContent =
+                new DualDisplayAreaGroupPolicyTest.DualDisplayContent
+                 .Builder(mAtm, 1000, 1000).build();
+        final DisplayArea.Tokens imeContainer = dualDisplayContent.getImeContainer();
+        // Put the ImeContainer to the first sub-RootDisplayArea
+        dualDisplayContent.mFirstRoot.placeImeContainer(imeContainer);
+
+        assertThat(imeContainer.getRootDisplayArea()).isEqualTo(dualDisplayContent.mFirstRoot);
+
+        // Simulate the behavior to show IME switch dialog: its context switches to register to
+        // context created WindowToken.
+        WindowToken windowContextCreatedToken = new WindowToken.Builder(mWm, mClientToken,
+                TYPE_INPUT_METHOD_DIALOG)
+                .setDisplayContent(dualDisplayContent)
+                .setFromClientToken(true)
+                .build();
+        mController.registerWindowContainerListener(mClientToken, windowContextCreatedToken,
+                TEST_UID, TYPE_INPUT_METHOD_DIALOG, null /* options */);
+
+        assertThat(mController.getContainer(mClientToken)).isEqualTo(windowContextCreatedToken);
+
+        // Remove WindowToken
+        windowContextCreatedToken.removeImmediately();
+
+        // Now context should listen to ImeContainer.
+        assertThat(mController.getContainer(mClientToken)).isEqualTo(imeContainer);
+    }
+
     private class TestWindowTokenClient extends IWindowToken.Stub {
         private Configuration mConfiguration;
         private int mDisplayId;
diff --git a/services/usage/java/com/android/server/usage/StorageStatsManagerInternal.java b/services/usage/java/com/android/server/usage/StorageStatsManagerInternal.java
deleted file mode 100644
index 47760ef..0000000
--- a/services/usage/java/com/android/server/usage/StorageStatsManagerInternal.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.usage;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.content.pm.PackageStats;
-
-/**
- * StorageStatsManager local system service interface.
- *
- * Only for use within the system server.
- */
-public abstract class StorageStatsManagerInternal {
-    /**
-     * Class used to augment {@link PackageStats} with the data stored by the system on
-     * behalf of apps in system specific directories
-     * ({@link android.os.Environment#getDataSystemDirectory},
-     * {@link android.os.Environment#getDataSystemCeDirectory}, etc).
-     */
-    public interface StorageStatsAugmenter {
-        void augmentStatsForPackage(@NonNull PackageStats stats,
-                @NonNull String packageName, @UserIdInt int userId,
-                boolean callerHasStatsPermission);
-        void augmentStatsForUid(@NonNull PackageStats stats, int uid,
-                boolean callerHasStatsPermission);
-    }
-
-    /**
-     * Register a {@link StorageStatsAugmenter}.
-     *
-     * @param augmenter the {@link StorageStatsAugmenter} object to be registered.
-     * @param tag the identifier to be used for debugging in logs/trace.
-     */
-    public abstract void registerStorageStatsAugmenter(@NonNull StorageStatsAugmenter augmenter,
-            @NonNull String tag);
-}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsManagerLocal.java b/services/usage/java/com/android/server/usage/StorageStatsManagerLocal.java
new file mode 100644
index 0000000..7cac820
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/StorageStatsManagerLocal.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usage;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.pm.PackageStats;
+import android.os.UserHandle;
+
+/**
+ * StorageStatsManager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public interface StorageStatsManagerLocal {
+    /**
+     * Class used to augment {@link PackageStats} with the data stored by the system on
+     * behalf of apps in system specific directories
+     * ({@link android.os.Environment#getDataSystemDirectory},
+     * {@link android.os.Environment#getDataSystemCeDirectory}, etc).
+     */
+    interface StorageStatsAugmenter {
+        /**
+         * Augments {@link PackageStats} with data stored by the system for the given package.
+         *
+         * @param stats                   Structure to modify with usage data
+         * @param packageName             Package name of the app whose data is stored by the
+         *                                system and needs to be added to {@code stats}.
+         * @param userHandle              Device user for which usage stats are being requested.
+         * @param canCallerAccessAllStats Whether the caller who is requesting the storage stats
+         *                                can query stats for packages other than itself. For
+         *                                example, holding the PACKAGE_USAGE_STATS permission is one
+         *                                way to accomplish this.
+         */
+        void augmentStatsForPackageForUser(
+                @NonNull PackageStats stats,
+                @NonNull String packageName,
+                @NonNull UserHandle userHandle,
+                boolean canCallerAccessAllStats);
+
+        /**
+         * Augments {@link PackageStats} with data stored by the system for the given uid.
+         *
+         * @param stats                   Structure to modify with usage data
+         * @param uid                     Unique app ID for the app instance whose stats are being
+         *                                requested.
+         * @param canCallerAccessAllStats Whether the caller who is requesting the storage stats
+         *                                can query stats for packages other than itself. For
+         *                                example, holding the PACKAGE_USAGE_STATS permission is one
+         *                                way to accomplish this.
+         */
+        void augmentStatsForUid(
+                @NonNull PackageStats stats, int uid, boolean canCallerAccessAllStats);
+
+        /**
+         * Augments {@link PackageStats} with data stored by the system for the given device user.
+         *
+         * @param stats      Structure to modify with usage data
+         * @param userHandle Device user whose data is stored by the system and needs to be added to
+         *                   {@code stats}.
+         */
+        void augmentStatsForUser(@NonNull PackageStats stats, @NonNull UserHandle userHandle);
+    }
+
+    /**
+     * Register a {@link StorageStatsAugmenter}.
+     *
+     * @param augmenter the {@link StorageStatsAugmenter} object to be registered.
+     * @param tag       the identifier to be used for debugging in logs/trace.
+     */
+    void registerStorageStatsAugmenter(
+            @NonNull StorageStatsAugmenter augmenter, @NonNull String tag);
+}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index a0a3909..b056de0 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -20,7 +20,7 @@
 
 import static com.android.internal.util.ArrayUtils.defeatNullable;
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
-import static com.android.server.usage.StorageStatsManagerInternal.StorageStatsAugmenter;
+import static com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -71,6 +71,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.IoThread;
+import com.android.server.LocalManagerRegistry;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.Installer;
@@ -152,7 +153,7 @@
             }
         });
 
-        LocalServices.addService(StorageStatsManagerInternal.class, new LocalService());
+        LocalManagerRegistry.addManager(StorageStatsManagerLocal.class, new LocalService());
     }
 
     private void invalidateMounts() {
@@ -335,9 +336,10 @@
                 throw new ParcelableException(new IOException(e.getMessage()));
             }
             if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
+                UserHandle userHandle = UserHandle.of(userId);
                 forEachStorageStatsAugmenter((storageStatsAugmenter) -> {
-                    storageStatsAugmenter.augmentStatsForPackage(stats,
-                            packageName, userId, callerHasStatsPermission);
+                    storageStatsAugmenter.augmentStatsForPackageForUser(stats,
+                            packageName, userHandle, callerHasStatsPermission);
                 }, "queryStatsForPackage");
             }
             return translate(stats);
@@ -430,6 +432,12 @@
         } catch (InstallerException e) {
             throw new ParcelableException(new IOException(e.getMessage()));
         }
+        if (volumeUuid == StorageManager.UUID_PRIVATE_INTERNAL) {
+            UserHandle userHandle = UserHandle.of(userId);
+            forEachStorageStatsAugmenter((storageStatsAugmenter) -> {
+                storageStatsAugmenter.augmentStatsForUser(stats, userHandle);
+            }, "queryStatsForUser");
+        }
         return translate(stats);
     }
 
@@ -784,7 +792,7 @@
         }
     }
 
-    private class LocalService extends StorageStatsManagerInternal {
+    private class LocalService implements StorageStatsManagerLocal {
         @Override
         public void registerStorageStatsAugmenter(
                 @NonNull StorageStatsAugmenter storageStatsAugmenter,
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl b/services/usage/java/com/android/server/usage/package-info.java
similarity index 72%
copy from apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
copy to services/usage/java/com/android/server/usage/package-info.java
index 37ce990..0719df4 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.aidl
+++ b/services/usage/java/com/android/server/usage/package-info.java
@@ -1,11 +1,11 @@
-/**
- * Copyright 2020, The Android Open Source Project
+/*
+ * 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
+ *      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,
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app.appsearch;
 
-/** {@hide} */
-parcelable AppSearchResult<ValueType>;
\ No newline at end of file
+/** @hide */
+package com.android.server.usage;
diff --git a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
index 0b47547..e9b7d95 100644
--- a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
+++ b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.telephony;
+package com.android.internal.telephony;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 0d6cd5a..98db291 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -43,7 +43,6 @@
 import android.os.UserManager;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
-import android.telephony.PackageChangeReceiver;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.SparseArray;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 84ea42f..33a9a96 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3473,6 +3473,21 @@
             "additional_nr_advanced_bands_int_array";
 
     /**
+     * This configuration allows the framework to control the NR advanced capable by protocol
+     * configuration options(PCO).
+     *
+     * If this config is 0, then the nr advanced capable is enabled.
+     * If this config is not 0 and PCO container with this config's address is 1, then the nr
+     * advanced capable is enabled.
+     * If this config is not 0 and PCO container with this config's address is 0, then the nr
+     * advanced capable is disabled.
+     *
+     * @hide
+     */
+    public static final String KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT =
+            "nr_advanced_capable_pco_id_int";
+
+    /**
      * Controls time in milliseconds until DcTracker reevaluates 5G connection state.
      * @hide
      */
@@ -5436,6 +5451,7 @@
         /* Default value is 1 hour. */
         sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
         sDefaults.putIntArray(KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY, new int[0]);
+        sDefaults.putInt(KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0);
         sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false);
         sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false);
         sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_SUB6_BOOL, false);
diff --git a/test-base/Android.bp b/test-base/Android.bp
index 9bd639b..b58aa11 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -32,7 +32,7 @@
 java_sdk_library {
     name: "android.test.base",
 
-    srcs: ["src/**/*.java"],
+    srcs: [":android-test-base-sources"],
 
     errorprone: {
         javacflags: ["-Xep:DepAnn:ERROR"],
@@ -66,7 +66,7 @@
     name: "android.test.base_static",
     installable: false,
 
-    srcs: ["src/**/*.java"],
+    srcs: [":android-test-base-sources"],
 
     errorprone: {
         javacflags: ["-Xep:DepAnn:ERROR"],
@@ -114,6 +114,12 @@
     ],
 }
 
+filegroup {
+    name: "android-test-base-sources",
+    srcs: ["src/**/*.java"],
+    path: "src",
+}
+
 // Make the current.txt available for use by the cts/tests/signature tests.
 // ========================================================================
 filegroup {
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index b83bce6..107292c 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -29,7 +29,7 @@
     name: "android.test.mock",
 
     srcs: [
-        "src/**/*.java",
+        ":android-test-mock-sources",
         // Note: Below are NOT APIs of this library. We only take APIs under
         // the android.test.mock package. They however provide private APIs that
         // android.test.mock APIs references to.
@@ -61,3 +61,9 @@
         "api/current.txt",
     ],
 }
+
+filegroup {
+    name: "android-test-mock-sources",
+    srcs: ["src/**/*.java"],
+    path: "src",
+}
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index fe007e39..c380ae3 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -29,7 +29,7 @@
 java_sdk_library {
     name: "android.test.runner",
 
-    srcs: ["src/**/*.java"],
+    srcs: [":android-test-runner-sources"],
 
     errorprone: {
         javacflags: ["-Xep:DepAnn:ERROR"],
@@ -76,7 +76,7 @@
 java_library_static {
     name: "repackaged.android.test.runner",
 
-    srcs: ["src/**/*.java"],
+    srcs: [":android-test-runner-sources"],
     exclude_srcs: [
         "src/android/test/ActivityUnitTestCase.java",
         "src/android/test/ApplicationTestCase.java",
@@ -108,3 +108,9 @@
         "api/current.txt",
     ],
 }
+
+filegroup {
+    name: "android-test-runner-sources",
+    srcs: ["src/**/*.java"],
+    path: "src",
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index f277e94..6702869 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -2777,8 +2777,9 @@
 
     private void grantUsingBackgroundNetworksPermissionForUid(
             final int uid, final String packageName) throws Exception {
-        when(mPackageManager.getPackageInfo(eq(packageName), eq(GET_PERMISSIONS)))
-                .thenReturn(buildPackageInfo(true, uid));
+        when(mPackageManager.getPackageInfo(
+                eq(packageName), eq(GET_PERMISSIONS | MATCH_ANY_USER)))
+                .thenReturn(buildPackageInfo(true /* hasSystemPermission */, uid));
         mService.mPermissionMonitor.onPackageAdded(packageName, uid);
     }
 
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 32c95f1..cf2c9c7 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -16,9 +16,14 @@
 
 package com.android.server;
 
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.INetd.IF_STATE_DOWN;
 import static android.net.INetd.IF_STATE_UP;
+import static android.net.IpSecManager.DIRECTION_FWD;
+import static android.net.IpSecManager.DIRECTION_IN;
+import static android.net.IpSecManager.DIRECTION_OUT;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
 
@@ -56,6 +61,7 @@
 import android.os.ParcelFileDescriptor;
 import android.system.Os;
 import android.test.mock.MockContext;
+import android.util.ArraySet;
 
 import androidx.test.filters.SmallTest;
 
@@ -71,6 +77,7 @@
 import java.net.Socket;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Set;
 
 /** Unit tests for {@link IpSecService}. */
 @SmallTest
@@ -119,7 +126,18 @@
     AppOpsManager mMockAppOps = mock(AppOpsManager.class);
     ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class);
 
-    MockContext mMockContext = new MockContext() {
+    TestContext mTestContext = new TestContext();
+
+    private class TestContext extends MockContext {
+        private Set<String> mAllowedPermissions = new ArraySet<>(Arrays.asList(
+                android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
+                android.Manifest.permission.NETWORK_STACK,
+                PERMISSION_MAINLINE_NETWORK_STACK));
+
+        private void setAllowedPermissions(String... permissions) {
+            mAllowedPermissions = new ArraySet<>(permissions);
+        }
+
         @Override
         public Object getSystemService(String name) {
             switch(name) {
@@ -147,20 +165,22 @@
 
         @Override
         public void enforceCallingOrSelfPermission(String permission, String message) {
-            if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
+            if (mAllowedPermissions.contains(permission)) {
                 return;
+            } else {
+                throw new SecurityException("Unavailable permission requested");
             }
-            throw new SecurityException("Unavailable permission requested");
         }
 
         @Override
         public int checkCallingOrSelfPermission(String permission) {
-            if (android.Manifest.permission.NETWORK_STACK.equals(permission)) {
+            if (mAllowedPermissions.contains(permission)) {
                 return PERMISSION_GRANTED;
+            } else {
+                return PERMISSION_DENIED;
             }
-            throw new UnsupportedOperationException();
         }
-    };
+    }
 
     INetd mMockNetd;
     PackageManager mMockPkgMgr;
@@ -194,7 +214,7 @@
         mMockNetd = mock(INetd.class);
         mMockPkgMgr = mock(PackageManager.class);
         mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
-        mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
+        mIpSecService = new IpSecService(mTestContext, mMockIpSecSrvConfig);
 
         // Injecting mock netd
         when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
@@ -664,6 +684,21 @@
 
         assertNotNull(createTunnelResp);
         assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
+        for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT, DIRECTION_FWD}) {
+            for (int selAddrFamily : ADDRESS_FAMILIES) {
+                verify(mMockNetd).ipSecAddSecurityPolicy(
+                        eq(mUid),
+                        eq(selAddrFamily),
+                        eq(direction),
+                        anyString(),
+                        anyString(),
+                        eq(0),
+                        anyInt(), // iKey/oKey
+                        anyInt(), // mask
+                        eq(createTunnelResp.resourceId));
+            }
+        }
+
         return createTunnelResp;
     }
 
@@ -798,16 +833,51 @@
     }
 
     @Test
-    public void testApplyTunnelModeTransform() throws Exception {
-        verifyApplyTunnelModeTransformCommon(false);
+    public void testApplyTunnelModeTransformOutbound() throws Exception {
+        verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
     }
 
     @Test
-    public void testApplyTunnelModeTransformReleasedSpi() throws Exception {
-        verifyApplyTunnelModeTransformCommon(true);
+    public void testApplyTunnelModeTransformOutboundNonNetworkStack() throws Exception {
+        mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
+        verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
     }
 
-    public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply) throws Exception {
+    @Test
+    public void testApplyTunnelModeTransformOutboundReleasedSpi() throws Exception {
+        verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_OUT);
+    }
+
+    @Test
+    public void testApplyTunnelModeTransformInbound() throws Exception {
+        verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
+    }
+
+    @Test
+    public void testApplyTunnelModeTransformInboundNonNetworkStack() throws Exception {
+        mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
+        verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
+    }
+
+    @Test
+    public void testApplyTunnelModeTransformForward() throws Exception {
+        verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
+    }
+
+    @Test
+    public void testApplyTunnelModeTransformForwardNonNetworkStack() throws Exception {
+        mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
+
+        try {
+            verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
+            fail("Expected security exception due to use of forward policies without NETWORK_STACK"
+                     + " or MAINLINE_NETWORK_STACK permission");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply, int direction)
+            throws Exception {
         IpSecConfig ipSecConfig = new IpSecConfig();
         ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
@@ -825,17 +895,17 @@
         int transformResourceId = createTransformResp.resourceId;
         int tunnelResourceId = createTunnelResp.resourceId;
         mIpSecService.applyTunnelModeTransform(
-                tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);
+                tunnelResourceId, direction, transformResourceId, BLESSED_PACKAGE);
 
         for (int selAddrFamily : ADDRESS_FAMILIES) {
             verify(mMockNetd)
                     .ipSecUpdateSecurityPolicy(
                             eq(mUid),
                             eq(selAddrFamily),
-                            eq(IpSecManager.DIRECTION_OUT),
+                            eq(direction),
                             anyString(),
                             anyString(),
-                            eq(TEST_SPI),
+                            eq(direction == DIRECTION_OUT ? TEST_SPI : 0),
                             anyInt(), // iKey/oKey
                             anyInt(), // mask
                             eq(tunnelResourceId));
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index d7535a9..02a5808 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -479,13 +479,14 @@
     public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
                 Arrays.asList(new PackageInfo[] {
-                        buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1),
-                        buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1),
-                        buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1),
-                        buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1)
+                        buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1),
+                        buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1),
+                        buildPackageInfo(false /* hasSystemPermission */, MOCK_UID2, MOCK_USER1),
+                        buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1)
                 }));
-        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
-                buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1),
+                eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+                buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1));
         mPermissionMonitor.startMonitoring();
         // Every app on user 0 except MOCK_UID2 are under VPN.
         final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
@@ -530,11 +531,12 @@
     public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
         when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
                 Arrays.asList(new PackageInfo[] {
-                        buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1),
-                        buildPackageInfo(false, VPN_UID, MOCK_USER1)
+                        buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1),
+                        buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1)
                 }));
-        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
-                        buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+        when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1),
+                eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+                buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1));
 
         mPermissionMonitor.startMonitoring();
         final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index eedaac4..39f7386 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -16,8 +16,11 @@
 
 package com.android.server.vcn;
 
+import static android.net.IpSecManager.DIRECTION_FWD;
 import static android.net.IpSecManager.DIRECTION_IN;
 import static android.net.IpSecManager.DIRECTION_OUT;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.net.ipsec.ike.exceptions.IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED;
@@ -54,6 +57,8 @@
 import android.net.ipsec.ike.exceptions.IkeException;
 import android.net.ipsec.ike.exceptions.IkeInternalException;
 import android.net.ipsec.ike.exceptions.IkeProtocolException;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
 import android.net.vcn.VcnManager.VcnErrorCode;
 
 import androidx.test.filters.SmallTest;
@@ -143,8 +148,9 @@
         assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
     }
 
-    @Test
-    public void testCreatedTransformsAreApplied() throws Exception {
+    private void verifyVcnTransformsApplied(
+            VcnGatewayConnection vcnGatewayConnection, boolean expectForwardTransform)
+            throws Exception {
         for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
             getChildSessionCallback().onIpSecTransformCreated(makeDummyIpSecTransform(), direction);
             mTestLooper.dispatchAll();
@@ -154,7 +160,40 @@
                             eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any());
         }
 
-        assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
+        verify(mIpSecSvc, expectForwardTransform ? times(1) : never())
+                .applyTunnelModeTransform(
+                        eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(DIRECTION_FWD), anyInt(), any());
+
+        assertEquals(vcnGatewayConnection.mConnectedState, vcnGatewayConnection.getCurrentState());
+    }
+
+    @Test
+    public void testCreatedTransformsAreApplied() throws Exception {
+        verifyVcnTransformsApplied(mGatewayConnection, false /* expectForwardTransform */);
+    }
+
+    @Test
+    public void testCreatedTransformsAreAppliedWithDun() throws Exception {
+        VcnGatewayConnectionConfig gatewayConfig =
+                VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(
+                        NET_CAPABILITY_INTERNET, NET_CAPABILITY_DUN);
+        VcnGatewayConnection gatewayConnection =
+                new VcnGatewayConnection(
+                        mVcnContext,
+                        TEST_SUB_GRP,
+                        TEST_SUBSCRIPTION_SNAPSHOT,
+                        gatewayConfig,
+                        mGatewayStatusCallback,
+                        true /* isMobileDataEnabled */,
+                        mDeps);
+        gatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
+        final VcnIkeSession session =
+                gatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network);
+        gatewayConnection.setIkeSession(session);
+        gatewayConnection.transitionTo(gatewayConnection.mConnectedState);
+        mTestLooper.dispatchAll();
+
+        verifyVcnTransformsApplied(gatewayConnection, true /* expectForwardTransform */);
     }
 
     @Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 284f1f8..1ecb4c9 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -220,7 +220,7 @@
     protected VcnChildSessionCallback getChildSessionCallback() {
         ArgumentCaptor<ChildSessionCallback> captor =
                 ArgumentCaptor.forClass(ChildSessionCallback.class);
-        verify(mDeps).newIkeSession(any(), any(), any(), any(), captor.capture());
+        verify(mDeps, atLeastOnce()).newIkeSession(any(), any(), any(), any(), captor.capture());
         return (VcnChildSessionCallback) captor.getValue();
     }
 
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index f2c3b86..812e208 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -1121,8 +1121,8 @@
 
                 // Skip all "uses-sdk" tags besides the very last tag. The android runtime only uses
                 // the attribute values from the last defined tag.
-                for (size_t i = 0; i < usesSdkTagPositions.size() - 1; i++) {
-                    tagsToSkip.emplace_back(usesSdkTagPositions[i]);
+                for (size_t i = 1; i < usesSdkTagPositions.size(); i++) {
+                    tagsToSkip.emplace_back(usesSdkTagPositions[i - 1]);
                 }
 
                 // Reset the position before parsing.
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 77c0872..ef3a62f 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -278,17 +278,19 @@
       printer->Println(StringPrintf(" entryCount=%zd", type.entries.size()));
 
       printer->Indent();
-      for (const ResourceEntry* entry : type.entries) {
+      for (const ResourceTableEntryView& entry : type.entries) {
         printer->Print("resource ");
-        printer->Print(entry->id.value_or_default(0).to_string());
+        printer->Print(ResourceId(package.id.value_or_default(0), type.id.value_or_default(0),
+                                  entry.id.value_or_default(0))
+                           .to_string());
         printer->Print(" ");
 
         // Write the name without the package (this is obvious and too verbose).
         printer->Print(to_string(type.type));
         printer->Print("/");
-        printer->Print(entry->name);
+        printer->Print(entry.name);
 
-        switch (entry->visibility.level) {
+        switch (entry.visibility.level) {
           case Visibility::Level::kPublic:
             printer->Print(" PUBLIC");
             break;
@@ -300,19 +302,24 @@
             break;
         }
 
-        if (entry->visibility.staged_api) {
+        if (entry.visibility.staged_api) {
           printer->Print(" STAGED");
         }
 
-        if (entry->overlayable_item) {
+        if (entry.overlayable_item) {
           printer->Print(" OVERLAYABLE");
         }
 
+        if (entry.staged_id) {
+          printer->Print(" STAGED_ID=");
+          printer->Print(entry.staged_id.value().id.to_string());
+        }
+
         printer->Println();
 
         if (options.show_values) {
           printer->Indent();
-          for (const auto& value : entry->values) {
+          for (const auto& value : entry.values) {
             printer->Print("(");
             printer->Print(value->config.to_string());
             printer->Print(") ");
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 1efabbb..f1e2da9 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -45,6 +45,7 @@
 namespace {
 constexpr const char* kPublicGroupTag = "public-group";
 constexpr const char* kStagingPublicGroupTag = "staging-public-group";
+constexpr const char* kStagingPublicGroupFinalTag = "staging-public-group-final";
 }  // namespace
 
 constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2";
@@ -109,6 +110,7 @@
   bool staged_api = false;
   bool allow_new = false;
   Maybe<OverlayableItem> overlayable_item;
+  Maybe<StagedId> staged_alias;
 
   std::string comment;
   std::unique_ptr<Value> value;
@@ -155,6 +157,10 @@
     res_builder.SetValue(std::move(res->value), res->config, res->product);
   }
 
+  if (res->staged_alias) {
+    res_builder.SetStagedId(res->staged_alias.value());
+  }
+
   bool error = false;
   if (!res->name.entry.empty()) {
     if (!table->AddResource(res_builder.Build(), diag)) {
@@ -532,6 +538,7 @@
       {"public", std::mem_fn(&ResourceParser::ParsePublic)},
       {"public-group", std::mem_fn(&ResourceParser::ParsePublicGroup)},
       {"staging-public-group", std::mem_fn(&ResourceParser::ParseStagingPublicGroup)},
+      {"staging-public-group-final", std::mem_fn(&ResourceParser::ParseStagingPublicGroupFinal)},
       {"string-array", std::mem_fn(&ResourceParser::ParseStringArray)},
       {"style", std::bind(&ResourceParser::ParseStyle, std::placeholders::_1, ResourceType::kStyle,
                           std::placeholders::_2, std::placeholders::_3)},
@@ -671,7 +678,7 @@
     if (bag_iter != elToBagMap.end()) {
       // Ensure we have a name (unless this is a <public-group> or <overlayable>).
       if (resource_type != kPublicGroupTag && resource_type != kStagingPublicGroupTag &&
-          resource_type != "overlayable") {
+          resource_type != kStagingPublicGroupFinalTag && resource_type != "overlayable") {
         if (!maybe_name) {
           diag_->Error(DiagMessage(out_resource->source)
                        << "<" << parser->element_name() << "> missing 'name' attribute");
@@ -1034,7 +1041,6 @@
       ParsedResource& entry_res = out_resource->child_resources.emplace_back(ParsedResource{
           .name = ResourceName{{}, *parsed_type, maybe_name.value().to_string()},
           .source = item_source,
-          .id = next_id,
           .comment = std::move(comment),
       });
 
@@ -1060,6 +1066,14 @@
                         });
 }
 
+bool ResourceParser::ParseStagingPublicGroupFinal(xml::XmlPullParser* parser,
+                                                  ParsedResource* out_resource) {
+  return ParseGroupImpl(parser, out_resource, kStagingPublicGroupFinalTag, diag_,
+                        [](ParsedResource& parsed_entry, ResourceId id) {
+                          parsed_entry.staged_alias = StagedId{id, parsed_entry.source};
+                        });
+}
+
 bool ResourceParser::ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource) {
   if (options_.visibility) {
     diag_->Error(DiagMessage(out_resource->source)
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 5c92def..2614997 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -115,6 +115,7 @@
   bool ParsePublic(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParsePublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseStagingPublicGroup(xml::XmlPullParser* parser, ParsedResource* out_resource);
+  bool ParseStagingPublicGroupFinal(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource);
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 45ea654..8ab1493 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -83,6 +83,20 @@
   return action(found, iter);
 }
 
+struct ConfigKey {
+  const ConfigDescription* config;
+  const StringPiece& product;
+};
+
+template <typename T>
+bool lt_config_key_ref(const T& lhs, const ConfigKey& rhs) {
+  int cmp = lhs->config.compare(*rhs.config);
+  if (cmp == 0) {
+    cmp = StringPiece(lhs->product).compare(rhs.product);
+  }
+  return cmp < 0;
+}
+
 }  // namespace
 
 ResourceTable::ResourceTable(ResourceTable::Validation validation) : validation_(validation) {
@@ -134,23 +148,10 @@
   });
 }
 
-struct ConfigKey {
-  const ConfigDescription* config;
-  const StringPiece& product;
-};
-
-bool lt_config_key_ref(const std::unique_ptr<ResourceConfigValue>& lhs, const ConfigKey& rhs) {
-  int cmp = lhs->config.compare(*rhs.config);
-  if (cmp == 0) {
-    cmp = StringPiece(lhs->product).compare(rhs.product);
-  }
-  return cmp < 0;
-}
-
 ResourceConfigValue* ResourceEntry::FindValue(const ConfigDescription& config,
                                               android::StringPiece product) {
   auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
-                               lt_config_key_ref);
+                               lt_config_key_ref<std::unique_ptr<ResourceConfigValue>>);
   if (iter != values.end()) {
     ResourceConfigValue* value = iter->get();
     if (value->config == config && StringPiece(value->product) == product) {
@@ -163,7 +164,7 @@
 const ResourceConfigValue* ResourceEntry::FindValue(const android::ConfigDescription& config,
                                                     android::StringPiece product) const {
   auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
-                               lt_config_key_ref);
+                               lt_config_key_ref<std::unique_ptr<ResourceConfigValue>>);
   if (iter != values.end()) {
     ResourceConfigValue* value = iter->get();
     if (value->config == config && StringPiece(value->product) == product) {
@@ -176,7 +177,7 @@
 ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config,
                                                       const StringPiece& product) {
   auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
-                               lt_config_key_ref);
+                               lt_config_key_ref<std::unique_ptr<ResourceConfigValue>>);
   if (iter != values.end()) {
     ResourceConfigValue* value = iter->get();
     if (value->config == config && StringPiece(value->product) == product) {
@@ -296,6 +297,7 @@
   return CollisionResult::kConflict;
 }
 
+namespace {
 template <typename T, typename Comparer>
 struct SortedVectorInserter : public Comparer {
   std::pair<bool, typename std::vector<T>::iterator> LowerBound(std::vector<T>& el,
@@ -313,7 +315,7 @@
     if (found) {
       return &*it;
     }
-    return &*el.insert(it, std::move(value));
+    return &*el.insert(it, std::forward<T>(value));
   }
 };
 
@@ -331,35 +333,77 @@
 };
 
 struct EntryViewComparer {
-  bool operator()(const ResourceEntry* lhs, const ResourceEntry* rhs) {
-    return less_than_struct_with_name_and_id<ResourceEntry, ResourceId>(
-        *lhs, std::make_pair(rhs->name, rhs->id));
+  bool operator()(const ResourceTableEntryView& lhs, const ResourceTableEntryView& rhs) {
+    return less_than_struct_with_name_and_id<ResourceTableEntryView, uint16_t>(
+        lhs, std::make_pair(rhs.name, rhs.id));
   }
 };
 
-ResourceTableView ResourceTable::GetPartitionedView() const {
-  ResourceTableView view;
+void InsertEntryIntoTableView(ResourceTableView& table, const ResourceTablePackage* package,
+                              const ResourceTableType* type, const std::string& entry_name,
+                              const Maybe<ResourceId>& id, const Visibility& visibility,
+                              const Maybe<AllowNew>& allow_new,
+                              const Maybe<OverlayableItem>& overlayable_item,
+                              const Maybe<StagedId>& staged_id,
+                              const std::vector<std::unique_ptr<ResourceConfigValue>>& values) {
   SortedVectorInserter<ResourceTablePackageView, PackageViewComparer> package_inserter;
   SortedVectorInserter<ResourceTableTypeView, TypeViewComparer> type_inserter;
-  SortedVectorInserter<const ResourceEntry*, EntryViewComparer> entry_inserter;
+  SortedVectorInserter<ResourceTableEntryView, EntryViewComparer> entry_inserter;
 
+  ResourceTablePackageView new_package{package->name,
+                                       id ? id.value().package_id() : Maybe<uint8_t>{}};
+  auto view_package = package_inserter.Insert(table.packages, std::move(new_package));
+
+  ResourceTableTypeView new_type{type->type, id ? id.value().type_id() : Maybe<uint8_t>{}};
+  auto view_type = type_inserter.Insert(view_package->types, std::move(new_type));
+
+  if (visibility.level == Visibility::Level::kPublic) {
+    // Only mark the type visibility level as public, it doesn't care about being private.
+    view_type->visibility_level = Visibility::Level::kPublic;
+  }
+
+  ResourceTableEntryView new_entry{.name = entry_name,
+                                   .id = id ? id.value().entry_id() : Maybe<uint16_t>{},
+                                   .visibility = visibility,
+                                   .allow_new = allow_new,
+                                   .overlayable_item = overlayable_item,
+                                   .staged_id = staged_id};
+  for (auto& value : values) {
+    new_entry.values.emplace_back(value.get());
+  }
+
+  entry_inserter.Insert(view_type->entries, std::move(new_entry));
+}
+}  // namespace
+
+const ResourceConfigValue* ResourceTableEntryView::FindValue(const ConfigDescription& config,
+                                                             android::StringPiece product) const {
+  auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
+                               lt_config_key_ref<const ResourceConfigValue*>);
+  if (iter != values.end()) {
+    const ResourceConfigValue* value = *iter;
+    if (value->config == config && StringPiece(value->product) == product) {
+      return value;
+    }
+  }
+  return nullptr;
+}
+
+ResourceTableView ResourceTable::GetPartitionedView(const ResourceTableViewOptions& options) const {
+  ResourceTableView view;
   for (const auto& package : packages) {
     for (const auto& type : package->types) {
       for (const auto& entry : type->entries) {
-        ResourceTablePackageView new_package{
-            package->name, entry->id ? entry->id.value().package_id() : Maybe<uint8_t>{}};
-        auto view_package = package_inserter.Insert(view.packages, std::move(new_package));
+        InsertEntryIntoTableView(view, package.get(), type.get(), entry->name, entry->id,
+                                 entry->visibility, entry->allow_new, entry->overlayable_item,
+                                 entry->staged_id, entry->values);
 
-        ResourceTableTypeView new_type{type->type,
-                                       entry->id ? entry->id.value().type_id() : Maybe<uint8_t>{}};
-        auto view_type = type_inserter.Insert(view_package->types, std::move(new_type));
-
-        if (entry->visibility.level == Visibility::Level::kPublic) {
-          // Only mark the type visibility level as public, it doesn't care about being private.
-          view_type->visibility_level = Visibility::Level::kPublic;
+        if (options.create_alias_entries && entry->staged_id) {
+          auto alias_id = entry->staged_id.value().id;
+          InsertEntryIntoTableView(view, package.get(), type.get(), entry->name, alias_id,
+                                   entry->visibility, entry->allow_new, entry->overlayable_item, {},
+                                   entry->values);
         }
-
-        entry_inserter.Insert(view_type->entries, entry.get());
       }
     }
   }
@@ -368,6 +412,8 @@
   // for the same resource type within the same package. For this reason, if there are types with
   // multiple type ids, each type needs to exist in its own package in order to be queried by name.
   std::vector<ResourceTablePackageView> new_packages;
+  SortedVectorInserter<ResourceTablePackageView, PackageViewComparer> package_inserter;
+  SortedVectorInserter<ResourceTableTypeView, TypeViewComparer> type_inserter;
   for (auto& package : view.packages) {
     // If a new package was already created for a different type within this package, then
     // we can reuse those packages for other types that need to be extracted from this package.
@@ -498,6 +544,10 @@
     entry->allow_new = res.allow_new.value();
   }
 
+  if (res.staged_id.has_value()) {
+    entry->staged_id = res.staged_id.value();
+  }
+
   if (res.value != nullptr) {
     auto config_value = entry->FindOrCreateValue(res.config, res.product);
     if (!config_value->value) {
@@ -575,6 +625,28 @@
   return {};
 }
 
+bool ResourceTable::RemoveResource(const ResourceNameRef& name, ResourceId id) const {
+  ResourceTablePackage* package = FindPackage(name.package);
+  if (package == nullptr) {
+    return {};
+  }
+
+  ResourceTableType* type = package->FindType(name.type);
+  if (type == nullptr) {
+    return {};
+  }
+
+  auto entry_it = std::equal_range(type->entries.begin(), type->entries.end(), name.entry,
+                                   NameEqualRange<ResourceEntry>{});
+  for (auto it = entry_it.first; it != entry_it.second; ++it) {
+    if ((*it)->id == id) {
+      type->entries.erase(it);
+      return true;
+    }
+  }
+  return false;
+}
+
 std::unique_ptr<ResourceTable> ResourceTable::Clone() const {
   std::unique_ptr<ResourceTable> new_table = util::make_unique<ResourceTable>();
   CloningValueTransformer cloner(&new_table->string_pool);
@@ -640,6 +712,11 @@
   return *this;
 }
 
+NewResourceBuilder& NewResourceBuilder::SetStagedId(StagedId staged_alias) {
+  res_.staged_id = std::move(staged_alias);
+  return *this;
+}
+
 NewResourceBuilder& NewResourceBuilder::SetAllowMangled(bool allow_mangled) {
   res_.allow_mangled = allow_mangled;
   return *this;
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 080ecc2..bae1d82 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -64,6 +64,12 @@
   std::string comment;
 };
 
+// Represents the staged resource id of a finalized resource.
+struct StagedId {
+  ResourceId id;
+  Source source;
+};
+
 struct Overlayable {
   Overlayable() = default;
    Overlayable(const android::StringPiece& name, const android::StringPiece& actor)
@@ -124,6 +130,9 @@
   // The declarations of this resource as overlayable for RROs
   Maybe<OverlayableItem> overlayable_item;
 
+  // The staged resource id for a finalized resource.
+  Maybe<StagedId> staged_id;
+
   // The resource's values for each configuration.
   std::vector<std::unique_ptr<ResourceConfigValue>> values;
 
@@ -194,14 +203,27 @@
   DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
 };
 
+struct ResourceTableEntryView {
+  std::string name;
+  Maybe<uint16_t> id;
+  Visibility visibility;
+  Maybe<AllowNew> allow_new;
+  Maybe<OverlayableItem> overlayable_item;
+  Maybe<StagedId> staged_id;
+  std::vector<const ResourceConfigValue*> values;
+
+  const ResourceConfigValue* FindValue(const android::ConfigDescription& config,
+                                       android::StringPiece product = {}) const;
+};
+
 struct ResourceTableTypeView {
   ResourceType type;
   Maybe<uint8_t> id;
   Visibility::Level visibility_level = Visibility::Level::kUndefined;
 
   // Entries sorted in ascending entry id order. If ids have not been assigned, the entries are
-  //  // sorted lexicographically.
-  std::vector<const ResourceEntry*> entries;
+  // sorted lexicographically.
+  std::vector<ResourceTableEntryView> entries;
 };
 
 struct ResourceTablePackageView {
@@ -212,6 +234,10 @@
   std::vector<ResourceTableTypeView> types;
 };
 
+struct ResourceTableViewOptions {
+  bool create_alias_entries = false;
+};
+
 struct ResourceTableView {
   // Packages sorted in ascending package id order. If ids have not been assigned, the packages are
   // sorted lexicographically.
@@ -237,6 +263,7 @@
   std::optional<Visibility> visibility;
   std::optional<OverlayableItem> overlayable;
   std::optional<AllowNew> allow_new;
+  std::optional<StagedId> staged_id;
   bool allow_mangled = false;
 };
 
@@ -249,6 +276,7 @@
   NewResourceBuilder& SetVisibility(Visibility id);
   NewResourceBuilder& SetOverlayable(OverlayableItem overlayable);
   NewResourceBuilder& SetAllowNew(AllowNew allow_new);
+  NewResourceBuilder& SetStagedId(StagedId id);
   NewResourceBuilder& SetAllowMangled(bool allow_mangled);
   NewResource Build();
 
@@ -273,7 +301,7 @@
 
   // Retrieves a sorted a view of the packages, types, and entries sorted in ascending resource id
   // order.
-  ResourceTableView GetPartitionedView() const;
+  ResourceTableView GetPartitionedView(const ResourceTableViewOptions& options = {}) const;
 
   struct SearchResult {
     ResourceTablePackage* package;
@@ -283,6 +311,7 @@
 
   Maybe<SearchResult> FindResource(const ResourceNameRef& name) const;
   Maybe<SearchResult> FindResource(const ResourceNameRef& name, ResourceId id) const;
+  bool RemoveResource(const ResourceNameRef& name, ResourceId id) const;
 
   // Returns the package struct with the given name, or nullptr if such a package does not
   // exist. The empty string is a valid package and typically is used to represent the
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index b45c040..95b7949 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -190,6 +190,12 @@
   uint32 overlayable_idx = 4;
 }
 
+// The staged resource ID definition of a finalized resource.
+message StagedId {
+  Source source = 1;
+  uint32 staged_id = 2;
+}
+
 // An entry ID in the range [0x0000, 0xffff].
 message EntryId {
   uint32 id = 1;
@@ -222,6 +228,9 @@
   // The set of values defined for this entry, each corresponding to a different
   // configuration/variant.
   repeated ConfigValue config_value = 6;
+
+  // The staged resource ID of this finalized resource.
+  StagedId staged_id = 7;
 }
 
 // A Configuration/Value pair.
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index df31087..3950f33 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -97,15 +97,15 @@
 
 static bool EmitResourceConfigValueDiff(
     IAaptContext* context, LoadedApk* apk_a, const ResourceTablePackageView& pkg_a,
-    const ResourceTableTypeView& type_a, const ResourceEntry* entry_a,
+    const ResourceTableTypeView& type_a, const ResourceTableEntryView& entry_a,
     const ResourceConfigValue* config_value_a, LoadedApk* apk_b,
     const ResourceTablePackageView& pkg_b, const ResourceTableTypeView& type_b,
-    const ResourceEntry* entry_b, const ResourceConfigValue* config_value_b) {
+    const ResourceTableEntryView& entry_b, const ResourceConfigValue* config_value_b) {
   Value* value_a = config_value_a->value.get();
   Value* value_b = config_value_b->value.get();
   if (!value_a->Equals(value_b)) {
     std::stringstream str_stream;
-    str_stream << "value " << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
+    str_stream << "value " << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
                << " config=" << config_value_a->config << " does not match:\n";
     value_a->Print(&str_stream);
     str_stream << "\n vs \n";
@@ -118,32 +118,32 @@
 
 static bool EmitResourceEntryDiff(IAaptContext* context, LoadedApk* apk_a,
                                   const ResourceTablePackageView& pkg_a,
-                                  const ResourceTableTypeView& type_a, const ResourceEntry* entry_a,
-                                  LoadedApk* apk_b, const ResourceTablePackageView& pkg_b,
+                                  const ResourceTableTypeView& type_a,
+                                  const ResourceTableEntryView& entry_a, LoadedApk* apk_b,
+                                  const ResourceTablePackageView& pkg_b,
                                   const ResourceTableTypeView& type_b,
-                                  const ResourceEntry* entry_b) {
+                                  const ResourceTableEntryView& entry_b) {
   bool diff = false;
-  for (const std::unique_ptr<ResourceConfigValue>& config_value_a : entry_a->values) {
-    auto config_value_b = entry_b->FindValue(config_value_a->config);
+  for (const ResourceConfigValue* config_value_a : entry_a.values) {
+    auto config_value_b = entry_b.FindValue(config_value_a->config);
     if (!config_value_b) {
       std::stringstream str_stream;
-      str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
+      str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
                  << " config=" << config_value_a->config;
       EmitDiffLine(apk_b->GetSource(), str_stream.str());
       diff = true;
     } else {
-      diff |=
-          EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a.get(),
-                                      apk_b, pkg_b, type_b, entry_b, config_value_b);
+      diff |= EmitResourceConfigValueDiff(context, apk_a, pkg_a, type_a, entry_a, config_value_a,
+                                          apk_b, pkg_b, type_b, entry_b, config_value_b);
     }
   }
 
   // Check for any newly added config values.
-  for (const std::unique_ptr<ResourceConfigValue>& config_value_b : entry_b->values) {
-    auto config_value_a = entry_a->FindValue(config_value_b->config);
+  for (const ResourceConfigValue* config_value_b : entry_b.values) {
+    auto config_value_a = entry_a.FindValue(config_value_b->config);
     if (!config_value_a) {
       std::stringstream str_stream;
-      str_stream << "new config " << pkg_b.name << ":" << type_b.type << "/" << entry_b->name
+      str_stream << "new config " << pkg_b.name << ":" << type_b.type << "/" << entry_b.name
                  << " config=" << config_value_b->config;
       EmitDiffLine(apk_b->GetSource(), str_stream.str());
       diff = true;
@@ -164,36 +164,35 @@
     if (entry_b_iter == type_b.entries.end()) {
       // Type A contains a type that type B does not have.
       std::stringstream str_stream;
-      str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << (*entry_a_iter)->name;
+      str_stream << "missing " << pkg_a.name << ":" << type_a.type << "/" << entry_a_iter->name;
       EmitDiffLine(apk_a->GetSource(), str_stream.str());
       diff = true;
     } else if (entry_a_iter == type_a.entries.end()) {
       // Type B contains a type that type A does not have.
       std::stringstream str_stream;
-      str_stream << "new entry " << pkg_b.name << ":" << type_b.type << "/"
-                 << (*entry_b_iter)->name;
+      str_stream << "new entry " << pkg_b.name << ":" << type_b.type << "/" << entry_b_iter->name;
       EmitDiffLine(apk_b->GetSource(), str_stream.str());
       diff = true;
     } else {
       const auto& entry_a = *entry_a_iter;
       const auto& entry_b = *entry_b_iter;
-      if (IsSymbolVisibilityDifferent(entry_a->visibility, entry_b->visibility)) {
+      if (IsSymbolVisibilityDifferent(entry_a.visibility, entry_b.visibility)) {
         std::stringstream str_stream;
-        str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
+        str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
                    << " has different visibility (";
-        if (entry_b->visibility.staged_api) {
+        if (entry_b.visibility.staged_api) {
           str_stream << "STAGED ";
         }
-        if (entry_b->visibility.level == Visibility::Level::kPublic) {
+        if (entry_b.visibility.level == Visibility::Level::kPublic) {
           str_stream << "PUBLIC";
         } else {
           str_stream << "PRIVATE";
         }
         str_stream << " vs ";
-        if (entry_a->visibility.staged_api) {
+        if (entry_a.visibility.staged_api) {
           str_stream << "STAGED ";
         }
-        if (entry_a->visibility.level == Visibility::Level::kPublic) {
+        if (entry_a.visibility.level == Visibility::Level::kPublic) {
           str_stream << "PUBLIC";
         } else {
           str_stream << "PRIVATE";
@@ -201,19 +200,19 @@
         str_stream << ")";
         EmitDiffLine(apk_b->GetSource(), str_stream.str());
         diff = true;
-      } else if (IsIdDiff(entry_a->visibility.level, entry_a->id, entry_b->visibility.level,
-                          entry_b->id)) {
+      } else if (IsIdDiff(entry_a.visibility.level, entry_a.id, entry_b.visibility.level,
+                          entry_b.id)) {
         std::stringstream str_stream;
-        str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a->name
+        str_stream << pkg_a.name << ":" << type_a.type << "/" << entry_a.name
                    << " has different public ID (";
-        if (entry_b->id) {
-          str_stream << "0x" << std::hex << entry_b->id.value();
+        if (entry_b.id) {
+          str_stream << "0x" << std::hex << entry_b.id.value();
         } else {
           str_stream << "none";
         }
         str_stream << " vs ";
-        if (entry_a->id) {
-          str_stream << "0x " << std::hex << entry_a->id.value();
+        if (entry_a.id) {
+          str_stream << "0x " << std::hex << entry_a.id.value();
         } else {
           str_stream << "none";
         }
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 3118eb8..430c184 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -402,8 +402,39 @@
   EXPECT_THAT(client_r_contents, HasSubstr(" com.example.lib.R.attr.foo, 0x7f010000"));
 }
 
-TEST_F(LinkTest, StagedAndroidApi) {
-  StdErrDiagnostics diag;
+struct SourceXML {
+  std::string res_file_path;
+  std::string file_contents;
+};
+
+static void BuildApk(const std::vector<SourceXML>& source_files, const std::string& apk_path,
+                     LinkCommandBuilder&& link_args, CommandTestFixture* fixture,
+                     IDiagnostics* diag) {
+  TemporaryDir res_dir;
+  TemporaryDir compiled_res_dir;
+  for (auto& source_file : source_files) {
+    ASSERT_TRUE(fixture->CompileFile(res_dir.path + source_file.res_file_path,
+                                     source_file.file_contents, compiled_res_dir.path, diag));
+  }
+  ASSERT_TRUE(fixture->Link(
+      link_args.AddCompiledResDir(compiled_res_dir.path, diag).Build(apk_path), diag));
+}
+
+static void BuildSDK(const std::vector<SourceXML>& source_files, const std::string& apk_path,
+                     const std::string& java_root_path, CommandTestFixture* fixture,
+                     IDiagnostics* diag) {
+  auto android_manifest = ManifestBuilder(fixture).SetPackageName("android").Build();
+
+  auto android_link_args = LinkCommandBuilder(fixture)
+                               .SetManifestFile(android_manifest)
+                               .AddParameter("--private-symbols", "com.android.internal")
+                               .AddParameter("--java", java_root_path);
+
+  BuildApk(source_files, apk_path, std::move(android_link_args), fixture, diag);
+}
+
+static void BuildNonFinalizedSDK(const std::string& apk_path, const std::string& java_path,
+                                 CommandTestFixture* fixture, IDiagnostics* diag) {
   const std::string android_values =
       R"(<resources>
           <public type="attr" name="finalized_res" id="0x01010001"/>
@@ -413,6 +444,10 @@
             <public name="staged_s_res" />
           </staging-public-group>
 
+          <staging-public-group type="string" first-id="0x01fd0080">
+            <public name="staged_s_string" />
+          </staging-public-group>
+
           <!-- SV2 staged attributes (support staged resources in a separate type id) -->
           <staging-public-group type="attr" first-id="0x01ff0049">
             <public name="staged_s2_res" />
@@ -423,46 +458,90 @@
             <public name="staged_t_res" />
           </staging-public-group>
 
-          <staging-public-group type="string" first-id="0x01fd0072">
-            <public name="staged_t_string" />
+          <attr name="finalized_res" />
+          <attr name="staged_s_res" />
+          <attr name="staged_s2_res" />
+          <attr name="staged_t_res" />
+          <string name="staged_s_string">Hello</string>
+         </resources>)";
+
+  SourceXML source_xml{.res_file_path = "/res/values/values.xml", .file_contents = android_values};
+  BuildSDK({source_xml}, apk_path, java_path, fixture, diag);
+}
+
+static void BuildFinalizedSDK(const std::string& apk_path, const std::string& java_path,
+                              CommandTestFixture* fixture, IDiagnostics* diag) {
+  const std::string android_values =
+      R"(<resources>
+          <public type="attr" name="finalized_res" id="0x01010001"/>
+          <public type="attr" name="staged_s_res" id="0x01010002"/>
+          <public type="attr" name="staged_s2_res" id="0x01010003"/>
+          <public type="string" name="staged_s_string" id="0x01020000"/>
+
+          <!-- S staged attributes (support staged resources in the same type id) -->
+          <staging-public-group-final type="attr" first-id="0x01010050">
+            <public name="staged_s_res" />
+          </staging-public-group-final>
+
+          <staging-public-group-final type="string" first-id="0x01fd0080">
+            <public name="staged_s_string" />
+          </staging-public-group-final>
+
+          <!-- SV2 staged attributes (support staged resources in a separate type id) -->
+          <staging-public-group-final type="attr" first-id="0x01ff0049">
+            <public name="staged_s2_res" />
+          </staging-public-group-final>
+
+          <!-- T staged attributes (support staged resources in multiple separate type ids) -->
+          <staging-public-group type="attr" first-id="0x01fe0063">
+            <public name="staged_t_res" />
           </staging-public-group>
 
           <attr name="finalized_res" />
           <attr name="staged_s_res" />
           <attr name="staged_s2_res" />
           <attr name="staged_t_res" />
-          <string name="staged_t_string">Hello</string>
+          <string name="staged_s_string">Hello</string>
          </resources>)";
 
+  SourceXML source_xml{.res_file_path = "/res/values/values.xml", .file_contents = android_values};
+  BuildSDK({source_xml}, apk_path, java_path, fixture, diag);
+}
+
+static void BuildAppAgainstSDK(const std::string& apk_path, const std::string& java_path,
+                               const std::string& sdk_path, CommandTestFixture* fixture,
+                               IDiagnostics* diag) {
   const std::string app_values =
       R"(<resources xmlns:android="http://schemas.android.com/apk/res/android">
            <attr name="bar" />
+           <style name="MyStyle">
+             <item name="android:staged_s_res">@android:string/staged_s_string</item>
+           </style>
            <declare-styleable name="ClientStyleable">
              <attr name="android:finalized_res" />
              <attr name="android:staged_s_res" />
              <attr name="bar" />
            </declare-styleable>
+           <public name="MyStyle" type="style" id="0x7f020000" />
          </resources>)";
 
-  const std::string android_res = GetTestPath("android-res");
-  ASSERT_TRUE(
-      CompileFile(GetTestPath("res/values/values.xml"), android_values, android_res, &diag));
+  SourceXML source_xml{.res_file_path = "/res/values/values.xml", .file_contents = app_values};
 
+  auto app_manifest = ManifestBuilder(fixture).SetPackageName("com.example.app").Build();
+
+  auto app_link_args = LinkCommandBuilder(fixture)
+                           .SetManifestFile(app_manifest)
+                           .AddParameter("--java", java_path)
+                           .AddParameter("-I", sdk_path);
+
+  BuildApk({source_xml}, apk_path, std::move(app_link_args), fixture, diag);
+}
+
+TEST_F(LinkTest, StagedAndroidApi) {
+  StdErrDiagnostics diag;
   const std::string android_apk = GetTestPath("android.apk");
-  const std::string android_java = GetTestPath("android_java");
-  // clang-format off
-  auto android_manifest = ManifestBuilder(this)
-      .SetPackageName("android")
-      .Build();
-
-  auto android_link_args = LinkCommandBuilder(this)
-      .SetManifestFile(android_manifest)
-      .AddParameter("--private-symbols", "com.android.internal")
-      .AddParameter("--java", android_java)
-      .AddCompiledResDir(android_res, &diag)
-      .Build(android_apk);
-  // clang-format on
-  ASSERT_TRUE(Link(android_link_args, &diag));
+  const std::string android_java = GetTestPath("android-java");
+  BuildNonFinalizedSDK(android_apk, android_java, this, &diag);
 
   const std::string android_r_java = android_java + "/android/R.java";
   std::string android_r_contents;
@@ -473,33 +552,17 @@
       HasSubstr("public static final int staged_s_res; static { staged_s_res=0x01010050; }"));
   EXPECT_THAT(
       android_r_contents,
+      HasSubstr("public static final int staged_s_string; static { staged_s_string=0x01fd0080; }"));
+  EXPECT_THAT(
+      android_r_contents,
       HasSubstr("public static final int staged_s2_res; static { staged_s2_res=0x01ff0049; }"));
   EXPECT_THAT(
       android_r_contents,
       HasSubstr("public static final int staged_t_res; static { staged_t_res=0x01fe0063; }"));
-  EXPECT_THAT(
-      android_r_contents,
-      HasSubstr("public static final int staged_t_string; static { staged_t_string=0x01fd0072; }"));
-
-  // Build an app that uses the framework attribute in a declare-styleable
-  const std::string client_res = GetTestPath("app-res");
-  ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), app_values, client_res, &diag));
 
   const std::string app_apk = GetTestPath("app.apk");
-  const std::string app_java = GetTestPath("app_java");
-  // clang-format off
-  auto app_manifest = ManifestBuilder(this)
-      .SetPackageName("com.example.app")
-      .Build();
-
-  auto app_link_args = LinkCommandBuilder(this)
-      .SetManifestFile(app_manifest)
-      .AddParameter("--java", app_java)
-      .AddParameter("-I", android_apk)
-      .AddCompiledResDir(client_res, &diag)
-      .Build(app_apk);
-  // clang-format on
-  ASSERT_TRUE(Link(app_link_args, &diag));
+  const std::string app_java = GetTestPath("app-java");
+  BuildAppAgainstSDK(app_apk, app_java, android_apk, this, &diag);
 
   const std::string client_r_java = app_java + "/com/example/app/R.java";
   std::string client_r_contents;
@@ -520,6 +583,10 @@
   ASSERT_TRUE(result.has_value());
   EXPECT_THAT(*result, Eq(0x01010050));
 
+  result = am.GetResourceId("android:string/staged_s_string");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_THAT(*result, Eq(0x01fd0080));
+
   result = am.GetResourceId("android:attr/staged_s2_res");
   ASSERT_TRUE(result.has_value());
   EXPECT_THAT(*result, Eq(0x01ff0049));
@@ -527,10 +594,88 @@
   result = am.GetResourceId("android:attr/staged_t_res");
   ASSERT_TRUE(result.has_value());
   EXPECT_THAT(*result, Eq(0x01fe0063));
+}
 
-  result = am.GetResourceId("android:string/staged_t_string");
+TEST_F(LinkTest, FinalizedAndroidApi) {
+  StdErrDiagnostics diag;
+  const std::string android_apk = GetTestPath("android.apk");
+  const std::string android_java = GetTestPath("android-java");
+  BuildFinalizedSDK(android_apk, android_java, this, &diag);
+
+  const std::string android_r_java = android_java + "/android/R.java";
+  std::string android_r_contents;
+  ASSERT_TRUE(android::base::ReadFileToString(android_r_java, &android_r_contents));
+  EXPECT_THAT(android_r_contents, HasSubstr("public static final int finalized_res=0x01010001;"));
+  EXPECT_THAT(android_r_contents, HasSubstr("public static final int staged_s_res=0x01010002;"));
+  EXPECT_THAT(android_r_contents, HasSubstr("public static final int staged_s_string=0x01020000;"));
+  EXPECT_THAT(android_r_contents, HasSubstr("public static final int staged_s2_res=0x01010003;"));
+  EXPECT_THAT(
+      android_r_contents,
+      HasSubstr("public static final int staged_t_res; static { staged_t_res=0x01fe0063; }"));
+  ;
+
+  // Build an application against the non-finalized SDK and then load it into an AssetManager with
+  // the finalized SDK.
+  const std::string non_finalized_android_apk = GetTestPath("non-finalized-android.apk");
+  const std::string non_finalized_android_java = GetTestPath("non-finalized-android-java");
+  BuildNonFinalizedSDK(non_finalized_android_apk, non_finalized_android_java, this, &diag);
+
+  const std::string app_apk = GetTestPath("app.apk");
+  const std::string app_java = GetTestPath("app-java");
+  BuildAppAgainstSDK(app_apk, app_java, non_finalized_android_apk, this, &diag);
+
+  android::AssetManager2 am;
+  auto android_asset = android::ApkAssets::Load(android_apk);
+  auto app_against_non_final = android::ApkAssets::Load(app_apk);
+  ASSERT_THAT(android_asset, NotNull());
+  ASSERT_THAT(app_against_non_final, NotNull());
+  ASSERT_TRUE(am.SetApkAssets({android_asset.get(), app_against_non_final.get()}));
+
+  auto result = am.GetResourceId("android:attr/finalized_res");
   ASSERT_TRUE(result.has_value());
-  EXPECT_THAT(*result, Eq(0x01fd0072));
+  EXPECT_THAT(*result, Eq(0x01010001));
+
+  result = am.GetResourceId("android:attr/staged_s_res");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_THAT(*result, Eq(0x01010002));
+
+  result = am.GetResourceId("android:string/staged_s_string");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_THAT(*result, Eq(0x01020000));
+
+  result = am.GetResourceId("android:attr/staged_s2_res");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_THAT(*result, Eq(0x01010003));
+
+  {
+    auto style = am.GetBag(0x7f020000);
+    ASSERT_TRUE(style.has_value());
+
+    auto& entry = (*style)->entries[0];
+    EXPECT_THAT(entry.key, Eq(0x01010002));
+    EXPECT_THAT(entry.value.dataType, Eq(android::Res_value::TYPE_REFERENCE));
+    EXPECT_THAT(entry.value.data, Eq(0x01020000));
+  }
+
+  // Re-compile the application against the finalized SDK and then load it into an AssetManager with
+  // the finalized SDK.
+  const std::string app_apk_respin = GetTestPath("app-respin.apk");
+  const std::string app_java_respin = GetTestPath("app-respin-java");
+  BuildAppAgainstSDK(app_apk_respin, app_java_respin, android_apk, this, &diag);
+
+  auto app_against_final = android::ApkAssets::Load(app_apk_respin);
+  ASSERT_THAT(app_against_final, NotNull());
+  ASSERT_TRUE(am.SetApkAssets({android_asset.get(), app_against_final.get()}));
+
+  {
+    auto style = am.GetBag(0x7f020000);
+    ASSERT_TRUE(style.has_value());
+
+    auto& entry = (*style)->entries[0];
+    EXPECT_THAT(entry.key, Eq(0x01010002));
+    EXPECT_THAT(entry.value.dataType, Eq(android::Res_value::TYPE_REFERENCE));
+    EXPECT_THAT(entry.value.data, Eq(0x01020000));
+  }
 }
 
 TEST_F(LinkTest, MacroSubstitution) {
diff --git a/tools/aapt2/compile/IdAssigner.cpp b/tools/aapt2/compile/IdAssigner.cpp
index 9a50b26..339b8af 100644
--- a/tools/aapt2/compile/IdAssigner.cpp
+++ b/tools/aapt2/compile/IdAssigner.cpp
@@ -129,11 +129,16 @@
     for (auto& type : package->types) {
       for (auto& entry : type->entries) {
         const ResourceName name(package->name, type->type, entry->name);
-        if (entry->id) {
-          if (!assigned_ids.ReserveId(name, entry->id.value(), entry->visibility,
-                                      context->GetDiagnostics())) {
-            return false;
-          }
+        if (entry->id && !assigned_ids.ReserveId(name, entry->id.value(), entry->visibility,
+                                                 context->GetDiagnostics())) {
+          return false;
+        }
+
+        auto v = entry->visibility;
+        v.staged_api = true;
+        if (entry->staged_id && !assigned_ids.ReserveId(name, entry->staged_id.value().id, v,
+                                                        context->GetDiagnostics())) {
+          return false;
         }
 
         if (assigned_id_map_) {
@@ -237,7 +242,7 @@
   if (type_id_ != id.type_id()) {
     // Currently there cannot be multiple type ids for a single type.
     std::stringstream error;
-    error << "type '" << name.type << "' already has ID " << std::hex << (int)id.type_id();
+    error << "type '" << name.type << "' already has ID " << std::hex << (int)type_id_;
     return unexpected(error.str());
   }
 
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 61ba09b..f2c6b15 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -135,7 +135,8 @@
     template <typename Predicate>
     void Filter(Predicate&& func) {
       children_.erase(std::remove_if(children_.begin(), children_.end(),
-                                     [&](const auto& e) { return func(e.get()); }));
+                                     [&](const auto& e) { return func(e.get()); }),
+                      children_.end());
     }
 
     /** Retrieves the list of children of the element. */
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index f1b350f..72eaa35 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -254,6 +254,12 @@
         }
         break;
 
+      case android::RES_TABLE_STAGED_ALIAS_TYPE:
+        if (!ParseStagedAliases(parser.chunk())) {
+          return false;
+        }
+        break;
+
       default:
         diag_->Warn(DiagMessage(source_)
                     << "unexpected chunk type "
@@ -489,6 +495,52 @@
   return true;
 }
 
+bool BinaryResourceParser::ParseStagedAliases(const ResChunk_header* chunk) {
+  auto header = ConvertTo<ResTable_staged_alias_header>(chunk);
+  if (!header) {
+    diag_->Error(DiagMessage(source_) << "corrupt ResTable_staged_alias_header chunk");
+    return false;
+  }
+
+  const auto ref_begin = reinterpret_cast<const ResTable_staged_alias_entry*>(
+      ((uint8_t*)header) + util::DeviceToHost32(header->header.headerSize));
+  const auto ref_end = ref_begin + util::DeviceToHost32(header->count);
+  for (auto ref_iter = ref_begin; ref_iter != ref_end; ++ref_iter) {
+    const auto staged_id = ResourceId(util::DeviceToHost32(ref_iter->stagedResId));
+    const auto finalized_id = ResourceId(util::DeviceToHost32(ref_iter->finalizedResId));
+
+    // If the staged alias chunk comes before the type chunks, the resource ids and resource name
+    // pairing will not exist at this point.
+    const auto iter = id_index_.find(finalized_id);
+    if (iter == id_index_.cend()) {
+      diag_->Error(DiagMessage(source_) << "failed to find resource name for finalized"
+                                        << " resource ID " << finalized_id);
+      return false;
+    }
+
+    // Set the staged id of the finalized resource.
+    const auto& resource_name = iter->second;
+    const StagedId staged_id_def{.id = staged_id};
+    if (!table_->AddResource(NewResourceBuilder(resource_name)
+                                 .SetId(finalized_id, OnIdConflict::CREATE_ENTRY)
+                                 .SetStagedId(staged_id_def)
+                                 .SetAllowMangled(true)
+                                 .Build(),
+                             diag_)) {
+      return false;
+    }
+
+    // Since a the finalized resource entry is cloned and added to the resource table under the
+    // staged resource id, remove the cloned resource entry from the table.
+    if (!table_->RemoveResource(resource_name, staged_id)) {
+      diag_->Error(DiagMessage(source_) << "failed to find resource entry for staged "
+                                        << " resource ID " << staged_id);
+      return false;
+    }
+  }
+  return true;
+}
+
 std::unique_ptr<Item> BinaryResourceParser::ParseValue(const ResourceNameRef& name,
                                                        const ConfigDescription& config,
                                                        const android::Res_value& value) {
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.h b/tools/aapt2/format/binary/BinaryResourceParser.h
index 13dd982..cd71d16 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.h
+++ b/tools/aapt2/format/binary/BinaryResourceParser.h
@@ -57,6 +57,7 @@
                  uint8_t package_id);
   bool ParseLibrary(const android::ResChunk_header* chunk);
   bool ParseOverlayable(const android::ResChunk_header* chunk);
+  bool ParseStagedAliases(const android::ResChunk_header* chunk);
 
   std::unique_ptr<Item> ParseValue(const ResourceNameRef& name,
                                    const android::ConfigDescription& config,
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 74ecf47..a9192e8 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -72,7 +72,7 @@
 }
 
 struct FlatEntry {
-  const ResourceEntry* entry;
+  const ResourceTableEntryView* entry;
   const Value* value;
 
   // The entry string pool index to the entry's name.
@@ -286,6 +286,10 @@
       return false;
     }
 
+    if (!FlattenAliases(buffer)) {
+      return false;
+    }
+
     pkg_writer.Finish();
     return true;
   }
@@ -351,8 +355,8 @@
 
     BigBuffer values_buffer(512);
     for (FlatEntry& flat_entry : *entries) {
-      CHECK(static_cast<size_t>(flat_entry.entry->id.value().entry_id()) < num_total_entries);
-      offsets[flat_entry.entry->id.value().entry_id()] = values_buffer.size();
+      CHECK(static_cast<size_t>(flat_entry.entry->id.value()) < num_total_entries);
+      offsets[flat_entry.entry->id.value()] = values_buffer.size();
       if (!FlattenValue(&flat_entry, &values_buffer)) {
         diag_->Error(DiagMessage()
                      << "failed to flatten resource '"
@@ -404,6 +408,26 @@
     return true;
   }
 
+  bool FlattenAliases(BigBuffer* buffer) {
+    if (aliases_.empty()) {
+      return true;
+    }
+
+    ChunkWriter alias_writer(buffer);
+    auto header =
+        alias_writer.StartChunk<ResTable_staged_alias_header>(RES_TABLE_STAGED_ALIAS_TYPE);
+    header->count = util::HostToDevice32(aliases_.size());
+
+    auto mapping = alias_writer.NextBlock<ResTable_staged_alias_entry>(aliases_.size());
+    for (auto& p : aliases_) {
+      mapping->stagedResId = util::HostToDevice32(p.first);
+      mapping->finalizedResId = util::HostToDevice32(p.second);
+      ++mapping;
+    }
+    alias_writer.Finish();
+    return true;
+  }
+
   bool FlattenOverlayable(BigBuffer* buffer) {
     std::set<ResourceId> seen_ids;
     std::map<std::string, OverlayableChunk> overlayable_chunks;
@@ -413,18 +437,17 @@
       CHECK(bool(type.id)) << "type must have an ID set when flattening <overlayable>";
       for (auto& entry : type.entries) {
         CHECK(bool(type.id)) << "entry must have an ID set when flattening <overlayable>";
-        if (!entry->overlayable_item) {
+        if (!entry.overlayable_item) {
           continue;
         }
 
-        const OverlayableItem& item = entry->overlayable_item.value();
+        const OverlayableItem& item = entry.overlayable_item.value();
 
         // Resource ids should only appear once in the resource table
-        ResourceId id =
-            android::make_resid(package_.id.value(), type.id.value(), entry->id.value().entry_id());
+        ResourceId id = android::make_resid(package_.id.value(), type.id.value(), entry.id.value());
         CHECK(seen_ids.find(id) == seen_ids.end())
             << "multiple overlayable definitions found for resource "
-            << ResourceName(package_.name, type.type, entry->name).to_string();
+            << ResourceName(package_.name, type.type, entry.name).to_string();
         seen_ids.insert(id);
 
         // Find the overlayable chunk with the specified name
@@ -452,9 +475,8 @@
 
         if (item.policies == 0) {
           context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
-                                                << "overlayable "
-                                                << entry->name
-                                                << " does not specify policy");
+                                            << "overlayable " << entry.name
+                                            << " does not specify policy");
           return false;
         }
 
@@ -520,7 +542,8 @@
   }
 
   bool FlattenTypeSpec(const ResourceTableTypeView& type,
-                       const std::vector<const ResourceEntry*>& sorted_entries, BigBuffer* buffer) {
+                       const std::vector<ResourceTableEntryView>& sorted_entries,
+                       BigBuffer* buffer) {
     ChunkWriter type_spec_writer(buffer);
     ResTable_typeSpec* spec_header =
         type_spec_writer.StartChunk<ResTable_typeSpec>(RES_TABLE_TYPE_SPEC_TYPE);
@@ -534,7 +557,7 @@
     // We can't just take the size of the vector. There may be holes in the
     // entry ID space.
     // Since the entries are sorted by ID, the last one will be the biggest.
-    const size_t num_entries = sorted_entries.back()->id.value().entry_id() + 1;
+    const size_t num_entries = sorted_entries.back().id.value() + 1;
 
     spec_header->entryCount = util::HostToDevice32(num_entries);
 
@@ -542,23 +565,23 @@
     // show for which configuration axis the resource changes.
     uint32_t* config_masks = type_spec_writer.NextBlock<uint32_t>(num_entries);
 
-    for (const ResourceEntry* entry : sorted_entries) {
-      const uint16_t entry_id = entry->id.value().entry_id();
+    for (const ResourceTableEntryView& entry : sorted_entries) {
+      const uint16_t entry_id = entry.id.value();
 
       // Populate the config masks for this entry.
       uint32_t& entry_config_masks = config_masks[entry_id];
-      if (entry->visibility.level == Visibility::Level::kPublic) {
+      if (entry.visibility.level == Visibility::Level::kPublic) {
         entry_config_masks |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
       }
-      if (entry->visibility.staged_api) {
+      if (entry.visibility.staged_api) {
         entry_config_masks |= util::HostToDevice32(ResTable_typeSpec::SPEC_STAGED_API);
       }
 
-      const size_t config_count = entry->values.size();
+      const size_t config_count = entry.values.size();
       for (size_t i = 0; i < config_count; i++) {
-        const ConfigDescription& config = entry->values[i]->config;
+        const ConfigDescription& config = entry.values[i]->config;
         for (size_t j = i + 1; j < config_count; j++) {
-          config_masks[entry_id] |= util::HostToDevice32(config.diff(entry->values[j]->config));
+          config_masks[entry_id] |= util::HostToDevice32(config.diff(entry.values[j]->config));
         }
       }
     }
@@ -590,7 +613,7 @@
       }
 
       // Since the entries are sorted by ID, the last ID will be the largest.
-      const size_t num_entries = type.entries.back()->id.value().entry_id() + 1;
+      const size_t num_entries = type.entries.back().id.value() + 1;
 
       // The binary resource table lists resource entries for each
       // configuration.
@@ -603,20 +626,26 @@
       // hardcoded string uses characters which make it an invalid resource name
       const std::string obfuscated_resource_name = "0_resource_name_obfuscated";
 
-      for (const ResourceEntry* entry : type.entries) {
+      for (const ResourceTableEntryView& entry : type.entries) {
+        if (entry.staged_id) {
+          aliases_.insert(std::make_pair(
+              entry.staged_id.value().id.id,
+              ResourceId(package_.id.value(), type.id.value(), entry.id.value()).id));
+        }
+
         uint32_t local_key_index;
-        ResourceName resource_name({}, type.type, entry->name);
+        ResourceName resource_name({}, type.type, entry.name);
         if (!collapse_key_stringpool_ ||
             name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) {
-          local_key_index = (uint32_t)key_pool_.MakeRef(entry->name).index();
+          local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
         } else {
           // resource isn't exempt from collapse, add it as obfuscated value
           local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index();
         }
         // Group values by configuration.
-        for (auto& config_value : entry->values) {
+        for (auto& config_value : entry.values) {
           config_to_entry_list_map[config_value->config].push_back(
-              FlatEntry{entry, config_value->value.get(), local_key_index});
+              FlatEntry{&entry, config_value->value.get(), local_key_index});
         }
       }
 
@@ -667,6 +696,7 @@
   StringPool key_pool_;
   bool collapse_key_stringpool_;
   const std::set<ResourceName>& name_collapse_exemptions_;
+  std::map<uint32_t, uint32_t> aliases_;
 };
 
 }  // namespace
@@ -684,7 +714,8 @@
   });
 
   // Write the ResTable header.
-  const auto& table_view = table->GetPartitionedView();
+  const auto& table_view =
+      table->GetPartitionedView(ResourceTableViewOptions{.create_alias_entries = true});
   ChunkWriter table_writer(buffer_);
   ResTable_header* table_header = table_writer.StartChunk<ResTable_header>(RES_TABLE_TYPE);
   table_header->packageCount = util::HostToDevice32(table_view.packages.size());
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index ec331df..236c381 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -498,10 +498,20 @@
                                               out_error)) {
           return false;
         }
-
         entry->overlayable_item = std::move(overlayable_item);
       }
 
+      if (pb_entry.has_staged_id()) {
+        const pb::StagedId& pb_staged_id = pb_entry.staged_id();
+
+        StagedId staged_id;
+        if (pb_staged_id.has_source()) {
+          DeserializeSourceFromPb(pb_staged_id.source(), src_pool, &staged_id.source);
+        }
+        staged_id.id = pb_staged_id.staged_id();
+        entry->staged_id = std::move(staged_id);
+      }
+
       ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
                        pb_entry.entry_id().id());
       if (resid.is_valid()) {
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index d2f0336..6042ba8 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -364,43 +364,52 @@
       static const char* obfuscated_resource_name = "0_resource_name_obfuscated";
       for (const auto& entry : type.entries) {
         pb::Entry* pb_entry = pb_type->add_entry();
-        if (entry->id) {
-          pb_entry->mutable_entry_id()->set_id(entry->id.value().entry_id());
+        if (entry.id) {
+          pb_entry->mutable_entry_id()->set_id(entry.id.value());
         }
-        ResourceName resource_name({}, type.type, entry->name);
+        ResourceName resource_name({}, type.type, entry.name);
         if (options.collapse_key_stringpool &&
             options.name_collapse_exemptions.find(resource_name) ==
             options.name_collapse_exemptions.end()) {
           pb_entry->set_name(obfuscated_resource_name);
         } else {
-          pb_entry->set_name(entry->name);
+          pb_entry->set_name(entry.name);
         }
 
         // Write the Visibility struct.
         pb::Visibility* pb_visibility = pb_entry->mutable_visibility();
-        pb_visibility->set_staged_api(entry->visibility.staged_api);
-        pb_visibility->set_level(SerializeVisibilityToPb(entry->visibility.level));
+        pb_visibility->set_staged_api(entry.visibility.staged_api);
+        pb_visibility->set_level(SerializeVisibilityToPb(entry.visibility.level));
         if (source_pool != nullptr) {
-          SerializeSourceToPb(entry->visibility.source, source_pool.get(),
+          SerializeSourceToPb(entry.visibility.source, source_pool.get(),
                               pb_visibility->mutable_source());
         }
-        pb_visibility->set_comment(entry->visibility.comment);
+        pb_visibility->set_comment(entry.visibility.comment);
 
-        if (entry->allow_new) {
+        if (entry.allow_new) {
           pb::AllowNew* pb_allow_new = pb_entry->mutable_allow_new();
           if (source_pool != nullptr) {
-            SerializeSourceToPb(entry->allow_new.value().source, source_pool.get(),
+            SerializeSourceToPb(entry.allow_new.value().source, source_pool.get(),
                                 pb_allow_new->mutable_source());
           }
-          pb_allow_new->set_comment(entry->allow_new.value().comment);
+          pb_allow_new->set_comment(entry.allow_new.value().comment);
         }
 
-        if (entry->overlayable_item) {
-          SerializeOverlayableItemToPb(entry->overlayable_item.value(), overlayables,
+        if (entry.overlayable_item) {
+          SerializeOverlayableItemToPb(entry.overlayable_item.value(), overlayables,
                                        source_pool.get(), pb_entry, out_table);
         }
 
-        for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
+        if (entry.staged_id) {
+          pb::StagedId* pb_staged_id = pb_entry->mutable_staged_id();
+          if (source_pool != nullptr) {
+            SerializeSourceToPb(entry.staged_id.value().source, source_pool.get(),
+                                pb_staged_id->mutable_source());
+          }
+          pb_staged_id->set_staged_id(entry.staged_id.value().id.id);
+        }
+
+        for (const ResourceConfigValue* config_value : entry.values) {
           pb::ConfigValue* pb_config_value = pb_entry->add_config_value();
           SerializeConfig(config_value->config, pb_config_value->mutable_config());
           pb_config_value->mutable_config()->set_product(config_value->product);
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index e563eda..38c811f 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -928,4 +928,27 @@
   EXPECT_THAT(deserialized->alias_namespaces, Eq(original->alias_namespaces));
 }
 
+TEST(ProtoSerializeTest, StagedId) {
+  CloningValueTransformer cloner(nullptr);
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+  std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+                                             .Add(NewResourceBuilder("com.app.a:string/foo")
+                                                      .SetStagedId(StagedId{.id = 0x01ff0001})
+                                                      .Build())
+                                             .Build();
+
+  ResourceTable new_table;
+  pb::ResourceTable pb_table;
+  MockFileCollection files;
+  std::string error;
+  SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
+  ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
+  EXPECT_THAT(error, IsEmpty());
+
+  auto result = new_table.FindResource(test::ParseNameOrDie("com.app.a:string/foo"));
+  ASSERT_TRUE(result);
+  ASSERT_TRUE(result.value().entry->staged_id);
+  EXPECT_THAT(result.value().entry->staged_id.value().id, Eq(ResourceId(0x01ff0001)));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index bc93ec6..22f4d18 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -151,6 +151,18 @@
     dst_entry->overlayable_item = std::move(src_entry->overlayable_item);
   }
 
+  if (src_entry->staged_id) {
+    if (dst_entry->staged_id &&
+        dst_entry->staged_id.value().id != src_entry->staged_id.value().id) {
+      context->GetDiagnostics()->Error(DiagMessage(src_entry->staged_id.value().source)
+                                       << "conflicting staged id declaration for resource '"
+                                       << src_entry->name << "'");
+      context->GetDiagnostics()->Error(DiagMessage(dst_entry->staged_id.value().source)
+                                       << "previous declaration here");
+    }
+    dst_entry->staged_id = std::move(src_entry->staged_id);
+  }
+
   return true;
 }
 
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index f94f0fe..285e5a1 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -80,9 +80,6 @@
 }
 
 void TestDirectoryFixture::WriteFile(const std::string& path, const std::string& contents) {
-  CHECK(util::StartsWith(path, temp_dir_))
-      << "Attempting to create a file outside of test temporary directory.";
-
   // Create any intermediate directories specified in the path
   auto pos = std::find(path.rbegin(), path.rend(), file::sDirSep);
   if (pos != path.rend()) {
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
index 7cfa784..9ceb204 100644
--- a/tools/codegen/src/com/android/codegen/Utils.kt
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -43,8 +43,8 @@
  * cccc dd
  */
 fun Iterable<Pair<String, String>>.columnize(separator: String = " | "): String {
-    val col1w = map { (a, _) -> a.length }.max()!!
-    val col2w = map { (_, b) -> b.length }.max()!!
+    val col1w = map { (a, _) -> a.length }.maxOrNull()!!
+    val col2w = map { (_, b) -> b.length }.maxOrNull()!!
     return map { it.first.padEnd(col1w) + separator + it.second.padEnd(col2w) }.joinToString("\n")
 }